15

I'm wondering what the best way is to map the http response from a get request to a class instead of a basic Javascript object.

In my current attempt I simple do new ClassName(data), but there might an obscure Angular specify and completely awesome way to do this that I don't know.

Here's my current code:

getPost(id:number){
    return this._http.get(this._postsUrl+'/'+id)
                .map(res => new Post(res.json().data))
                .do(data => console.log(data))
                .catch(this.handleError);
}

I need Post to be a class and not just an interface because I have methods inside.

I followed the HeroTutorial and the http "developer guide" along and in their getHeroes method they do:

getHeroes () {
return this.http.get(this._heroesUrl)
                .map(res => <Hero[]> res.json().data)
                .catch(this.handleError);
}

I somehow expected the <Hero[]> part to do just that: Take the Hero class and create new instances of it, but my tests show that it doesn't, this is pretty much just for Typescript to know what to expect.

Any ideas ? Thanks!

5
  • 4
    This isn't related to Angular or Http, but only to TypeScript => how to deserialize JSON to a concrete class instance. Commented Feb 23, 2016 at 9:30
  • 2
    new ClassName(data) is completely valid, you can chain operators and do mapping, filtering, reducing... Observables don't care what they wrap (; Commented Feb 23, 2016 at 9:47
  • @GünterZöchbauer Looks like you are right, a quick search of those words did return a lot of results. None of them are really what I wanted to hear, but I'll manage something knowing that there is no good way to do it. Commented Feb 23, 2016 at 10:04
  • Possible duplicate of How do I cast a JSON object to a typescript class Commented May 18, 2016 at 22:00
  • I don't consider any of the solutions on StackOverflow to be a comprehensive solution to the problem. So, I created an npm package angular-http-deserializer for this: npmjs.com/package/angular-http-deserializer#usage Commented Dec 20, 2018 at 17:13

3 Answers 3

17

I think that you could use the map method of JavaScript objects:

getHeroes () {
  return this.http.get(this._heroesUrl)
            .map(res => {
               return res.json().data.map((elt) => {
                 // Use elt to create an instance of Hero
                 return new Hero(...);
               });
             })
            .catch(this.handleError);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Great, this works like a charm! Should be marked as solution. Thanks, Thierry!
2

By setting the prototype on the object being returned I was able to get an instance of my class.

getHero () {
      return this.http.get(this._heroUrl)
            .map(response => {
                    let res = <Hero> response.json();
                    Object.setPrototypeOf(res, Hero.prototype);
                    return res;
                   })
            .catch(this.handleError);
}

My class was very simple with a parameterless constructor so this worked for me. For more complex classes I don't know if this would work.

Note: the above code is for getHero() not getHeroes(). I would assume I could do the same thing with a list by setting the prototype on each item in the array but I haven't tried/confirmed that.

Reference: I got the idea for this from this post by BMiner

1 Comment

This solution in particular suffers from poor performance, which I describe in my npm package documentation. github.com/windhandel/…
0

Good practice is to consume data from GET response using

Observable<Model>

(regarding to Angular documentation https://angular.io/guide/http) So...

// imports

import {HttpClient} from "@angular/common/http";

// in constructor parameter list

private http: HttpClient

// service method

getHeroes(): Observable<Hero[]> {return this.http.get<Hero[]>({url}, {options});}

You do not need to do anything more. I consider this approach as most friendly.

2 Comments

This does not attach the prototype and methods to the object. This is using Hero as an interface, not a class with methods on it.
suppose there is a class with attributes and methods how does this code will instantiate that object ?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.