4

Angular is converting from HttpModule to HttpClientModule and deprecating the former, as detailed at Difference between HTTP and HTTPClient in angular 4?.

However the Angular tutorial at https://angular.io/tutorial/toh-pt6 uses HttpModule, while the Fundamentals information at https://angular.io/guide/http uses HttpClientModule as detailed at https://github.com/angular/angular/issues/19280. The comparison is made more difficult by the tutorial using an in-memory server while the Fundamentals use a real web server.

I've tried to make the switch from HttpModule to HttpClientModule in the Angular tutorial code using a real web server and gotten some parts working but other parts are not working. It seems to work to change one of the getHeroes methods in hero.services.ts from

  getHeroes(): Promise<Hero[]> {
    return this.http.get(this.heroesUrl)
      .toPromise()
      .then(response => response.json().data as Hero[])
      .catch(this.handleError);
  }

to

  getHeroes(): Promise<Hero[]> {
    return this.httpClient.get(this.heroesUrl)
      .toPromise()
      .then(data => data['heroes'] as Hero[])
      .catch(this.handleError);
  }

though there may be ways this can be improved and this version may have problems I haven't discovered yet.

But I don't see an equivalent for the search method in hero-search.service.ts

  search(term: string): Observable<Hero[]> {
    return this.http
      .get(`api/heroes/?name=${term}`)
      .map(response => response.json().data as Hero[]);
  }

One should be able to dispense with map, but you can't use the same approach as above because there is an Observable instead of a Promise, and you get errors such as:

Type 'Observable<Object>' is not assignable to type 'Observable<Hero[]>'.

Has anyone converted the Heroes demo in the Angular tutorial to use HttpClientModule or knows how to convert the search code above?

alexKhymenko
  • 5,450
  • 23
  • 40
Mickey Segal
  • 841
  • 1
  • 10
  • 21

2 Answers2

4

While HttpClient parses the JSON response into an Object, it doesn't know what shape that object is. So you can specify what type the response will be:

return this.http
    .get<{ data: Hero[] }>(`api/heroes/?name=${term}`)
    .map(res => res.data);

Notice you can create interface for that:

interface ItemsResponse {
  data: Hero[];
}

return this.http
  .get<ItemsResponse>(`api/heroes/?name=${term}`)
  .map(res => res.data);

If you doubt what type of response will be or don't want to create interface then just use any:

return this.http
  .get<any>(`api/heroes/?name=${term}`)
  .map(res => res.data);

TOH-HttpClientModule Example

See also

yurzui
  • 205,937
  • 32
  • 433
  • 399
  • This solved the problem, as illustrated in https://plnkr.co/edit/uW3F0TPLqP9sSA4AdyGu?p=preview. In hero.service.ts I switched to using similar syntax in methods such as getHeroes instead of the code I gave above. But I wan't sure how to handle headers and post, and the create method is throwing the error "Cannot create property 'id' on string". Advice on those parts would be appreciated. – Mickey Segal Sep 24 '17 at 16:48
0

rewrite your component they removed response.json in httpClient no need to call response.json() anymore. If data is not right name for response, open console and look for the right name of return object.

search(term: string): Observable<Hero[]> {
return this.http
  .get(`api/heroes/?name=${term}`)
  .map(response => {
         console.log(response);
         return response['data'] as Hero[]
   });

}
alexKhymenko
  • 5,450
  • 23
  • 40
  • Object of Observable<{}|Hero[]> can't be assigned to Observable. – Ravinder Payal Nov 22 '17 at 07:56
  • Its probably that your hero class have required field and empty object can't be hero class due to required fields. – alexKhymenko Nov 22 '17 at 08:45
  • No, it's because the the httpClient can return two kinds of object. If server returned nothing it will return `{}`. And in subscription we have to write a logic for handling this situation. – Ravinder Payal Nov 22 '17 at 09:37