Angular2 parsing from JSON to object

25,619

It's because in Angular tutorial, json is in the data property.

As stated in the tutorial

Make no assumptions about the server API. Not all servers return an object with a data property.

If you are not wrapping your json with any property you can just use

private extractData(res: Response) {
  let body = res.json();
  return body || { }; //<--- not wrapped with data
}

Update:

Component code

 onSearch(terms: string) {    
    this.searchService.search(this.user, terms).subscribe(
      (response: SearchResponse) => {    // <--- cast here   
          console.log(response); 
      },
      error => {
          console.log(JSON.stringify(error));
      },
      () => { }
    );
 }
Share:
25,619
Ben
Author by

Ben

I'm a game developer (Unity, BennuGD, Div Game Studio) I'm a professional web developer (Angular) I'm a professional mobile app developer (Xamarin Forms)

Updated on September 19, 2020

Comments

  • Ben
    Ben over 3 years

    I'm trying to find the best way to cast my json object to Typescript object. I have a http get service which returns a list of user. My current version works, I have added from JSON function to all my model classes to make the mapping works:

    export class User {
    
        constructor(
            public pk: number,
            public username: string,
            public first_name: string,
            public last_name: string,
            public email: string,
            public profile: UserProfile, ) {
        }
    
        static fromJSON(json: any): User {
            let user = Object.create(User.prototype);
            Object.assign(user, json);
            user.profile = UserProfile.fromJSON(json.profile);
            return user;
        }
    }
    

    That works well. But there is something I don't get in the angular 2 doc. On the heroes tutorial, the JSON is automatically casted to object this way:

      getHeroes (): Observable<Hero[]> {
        return this.http.get(this.heroesUrl)
                        .map(this.extractData)
                        .catch(this.handleError);
      }
      private extractData(res: Response) {
        let body = res.json();
        return body.data || { };
      }
    

    I can't get this method to work on my case, I says that body.data is undefined. Does this method really works?

    EDIT:

    My http service doesn't returns an array of users. It returns a page which contains an array of users in its 'results' property.

    {
      "count": 2,
      "next": null,
      "previous": null,
      "results": [
        {
          "pk": 48,
          "first_name": "Jon",
          "last_name": "Does",
          "profile": {
            "pk": 46,
            "gender": "U"
          }
        },
        {
          "pk": 47,
          "first_name": "Pablo",
          "last_name": "Escobar",
          "profile": {
            "pk": 45,
            "gender": "M"
          }
        }
      ]
    }
    

    My service code:

     private extractData(res: Response) {
        let body = res.json().results;
        return body || {}; //<--- not wrapped with data
      }
    
      search(authUser: AuthUser, terms: string): Observable<User[]> {
        let headers = new Headers({
          'Content-Type': 'application/json',
          'X-CSRFToken': this.cookiesService.csrftoken,
          'Authorization': `Token ${authUser.token}`
        });
        let options = new RequestOptions({ headers: headers });
        return this.http.get(environment.server_url + 'user/?search=' + terms, options)
          .map(this.extractData);
        // .map((response: Response) => response.json());
      }
    

    My search component code:

     onSearch(terms: string) {    
        this.searchService.search(this.user, terms).subscribe(
          response => {       
              console.log(response); // Return array of object instead of array of user
          },
          error => {
              console.log(JSON.stringify(error));
          },
          () => { }
        );
     }
    

    EDIT 2:

    To make this case easier, I've wrote this simple code:

      test(){
        let json_text=` [
          {
            "id": 1,
            "text": "Jon Doe"
          },
          {
            "id": 1,
            "text": "Pablo Escobar"
          }
        ]`;
    
        console.log(<MyObject[]>JSON.parse(json_text)); // Array of objects
        console.log(MyObject.fromJSON(JSON.parse(json_text))); // Array of 'MyObject'
      }
    
    
    
    export class MyObject{
      id: number;
      text: string;
    
       static fromJSON(json: any): MyObject {
            let object = Object.create(MyObject.prototype);
            Object.assign(object, json);
            return object;
        }
    }
    
    • console.log(<MyObject[]>JSON.parse(json_text)) returns a list of Objects
    • console.log(MyObject.fromJSON(JSON.parse(json_text))) returns a list of MyObject
  • Ben
    Ben over 7 years
    Thank you. With your modification, it returns a list of Object instead of a list of User. Is there a way to fix it?
  • Sefa
    Sefa over 7 years
    Try uncommenting second map .map((res) => {res.result = <User>res.result});
  • Ben
    Ben over 7 years
    It returns an empty json {}
  • Sefa
    Sefa over 7 years
    at which point you get object array? When you subscribe at component or mapping at service?
  • Ben
    Ben over 7 years
    When I subscribe at component
  • Sefa
    Sefa over 7 years
    I think it's because your return type is Observable<User[]> but your json is not. Can you create SearchResponse class to wrap it all? Or just map results property of your response.
  • Ben
    Ben over 7 years
    I've tried with SearchResponse class but it still returns an Object instead.
  • Sefa
    Sefa over 7 years
    Have you also updated services return type? I don't have access to my work pc right now so i'm unable to test & give you an clear answer.
  • Ben
    Ben over 7 years
    Yes my service return type is Observable<SearchResponse>
  • Sefa
    Sefa over 7 years
    In my test, it returns SearchResponse with no problem. By the way, cast is only compile-time since javascript doesn't support static typing. Are you getting any type at compile time? If you can see the type at your ide it means it's working. You'll always get object at runtime.
  • Ben
    Ben over 7 years
    Please have a look at my EDIT2 part.
  • Ben
    Ben over 7 years
    Maybe I should create a separate post for the EDIT2 question?
  • Sefa
    Sefa over 7 years
    I couldn't seem to be able to reproduce this problem. I think it's best if you ask a new question because no one is going to read all this comments and find out you have a different problem now.
  • Ben
    Ben over 7 years
    Thank you, I will post a new question. And thank you for your time! (But saddly I cannot accept your reply as answer, I'm sorry about that :-( ).
  • Sefa
    Sefa over 7 years
    No worries.. :)