J'obtiens donc la structure JSON suivante de mon asp.net core api:

{
  "contentType": null,
  "serializerSettings": null,
  "statusCode": null,
  "value": {
     "productName": "Test",
     "shortDescription": "Test 123",
     "imageUri": "https://bla.com/bla",
     "productCode": null,
     "continuationToken": null
  }
}

J'ai la fonction dactylographiée suivante qui appelle l'API pour obtenir la réponse ci-dessus:

public externalProduct: ProductVM;


getProductExternal(code: string): Observable<ProductVM> {
    return this.http.get("api/product?productCode=" + code)
        .map((data: ProductVM) => {
            this.externalProduct = data; //not working...
            console.log("DATA: " + data);
            console.log("DATA: " + data['value']);
            return data;
        });    
}

ProductVM:

export interface ProductVM {

    productName: string;
    shortDescription: string;
    imageUri: string;
    productCode: string;
    continuationToken: string;
}

Mon problème est que je ne peux pas le désérialiser en ProductVM. Les journaux de la console produisent simplement [object Object]

Comment puis-je mapper le contenu de value dans ma réponse json à un objet ProductVM?

Est-il faux de dire que data est un ProductVM dans la fonction de carte? J'ai essayé beaucoup de combinaisons différentes mais je n'arrive pas à le faire fonctionner!

Je ne sais pas si je peux dire automatiquement à angular de mapper le tableau de valeurs dans la réponse json à un objet ProductVM ou si je dois fournir un constructeur au ProductVM class (c'est une interface en ce moment), et extraire manuellement les valeurs spécifiques dans le json?

3
DSF 16 nov. 2017 à 18:14

5 réponses

Meilleure réponse

L'objet data dans la méthode map chaînée à http est considéré comme un objet typé Object. Ce type n'a pas le membre value auquel vous devez accéder et par conséquent, le vérificateur de type n'est pas satisfait.

Les objets qui sont typés (qui ne sont pas any) ne peuvent être affectés qu'à des objets non typés ou du même type exact. Ici, vos données sont de type Object et ne peuvent pas être affectées à un autre objet de type ProductVM.

Une solution pour contourner la vérification de type consiste à convertir votre objet de données en un objet any non typé. Cela permettra d'accéder à n'importe quelle méthode ou membre, tout comme l'ancien Javascript.

getProductExternal(code: string): Observable<ProductVM> {
  return this.http.get("api/product?productCode=" + code)
    .map((data: any) => this.externalProduct = data.value);    
}

Une autre solution consiste à modifier votre API afin que les données puissent diffuser leur contenu avec data.json(). De cette façon, vous n'aurez pas à contourner la vérification de type puisque la méthode json () renvoie une valeur non typée.

Attention cependant car votre objet any n'aura pas de méthodes du ProductVM si jamais vous les ajoutez dans le futur. Vous devrez créer manuellement une instance avec new ProductVM() et Object.assign dessus pour accéder aux méthodes.

4
Adrien Brunelat 16 nov. 2017 à 16:43

J'ai utilisé cette approche dans un client qui utilise la méthode

HttpClient.get<GENERIC>(...). 

Maintenant ça marche. Quoi qu'il en soit, je ne comprends pas pourquoi je ne reçois pas un type de T en retour du client http, si je n'utilise pas la solution fournie dans la réponse ci-dessus.

Voici le client:

// get
get<T>(url: string, params?: [{key: string, value: string}]): Observable<T> {
var requestParams = new HttpParams()

if (params != undefined) {
  for (var kvp of params) {
    params.push(kvp);
  }
}

return this.httpClient.get<T>(url, {
  observe: 'body',
  headers: this.authHeaders,
  params: requestParams
}).pipe(
  map(
    res => <T>res
  )
);
}
0
Michael Staples 27 sept. 2018 à 12:56
getProductExternal(code: string): Observable<ProductVM> {
    return this.http.get("api/product?productCode=" + code)
        .map(data => {
            this.externalProduct = <ProductVM>data;
            console.log("DATA: " + this.externalProduct);
            return data;
        });    
}

Alors, nous convertissons d'abord la réponse en JSON. Je le stocke dans response juste pour le rendre plus propre. Ensuite, nous devons naviguer vers value, car dans vos données value se trouve l'objet qui correspond à ProductVM.

Je le ferais cependant comme ceci:

Service

getProductExternal(code: string): Observable<ProductVM> {
        return this.http.get(`api/product?productCode=${code}`)
            .map(data => <ProductVM>data)
            .catch((error: any) => Observable.throw(error.json().error || 'Server error'));    
    }

Composant

this.subscription = this.myService.getProductExternal(code).subscribe(
  product => this.externalProduct = product,
  error => console.warn(error)
);
1
SrAxi 16 nov. 2017 à 15:51

Avez-vous essayé de remplacer

this.externalProduct = data;

Avec

this.externalProduct = data.json();

J'espère que cela aide

1
Terry Pitz 16 nov. 2017 à 15:23

À partir de la documentation angulaire: réponse http Typechecking

Vous devez définir le type de données renvoyées lors de l'utilisation de new httpClient (depuis angular 4.3) => this.http.get < ProductVM > (...

public externalProduct: ProductVM;    
getProductExternal(code: string): Observable<ProductVM> {
        return this.http.get<ProductVM>("api/product?productCode=" + code)
            .map((data: ProductVM) => {
                this.externalProduct = data; // should be allowed by typescript now
                return data;
            });    
    }

Ainsi dactylographié devrait vous laisser en paix

2
Pierre Mallet 16 nov. 2017 à 16:06
47333159