Crowdpleasr
Crowdpleasr

Reputation: 4044

How to process json Observable

I'm receiving a complicated Object sent from my Express back-end, using res.json. (A list of members who have registered).

On the front-end, I'd like to convert the json response into an object that I can process in my template. Shouldn't I just be able to call JSON.parse() on the json response?

I've seen some proposed solutions that require the HttpClient get call to have a generic of the type of the object to be returned, i.e. get<MyObj>. (such as in this article Angular Http Call). Is there a way to do this without specifying in advance the return type from the get call? (I'd like to keep the front-end implementation as light and flexible as possible, and do all the data definitions in the back-end, then use the front-end to "read" the back-end data structure. The data structure is quite complicated and long, and it would save a lot of work if I can avoid repeating the data definition in both the back and front end).

Unfortunately, I haven't found a way yet, as for instance the editor tells me that JSON.parse expects a string parameter, while my HttpClient call returns an Object.

Here's the code I have so far:

member.service.ts:

constructor(private http: HttpClient) { }

ngOnInit() {
  this.getList();
}

getList(): Observable<any> {
    return this.http
      .get(`${this.host_url}list`,{responseType: 'json'})
  }

register.component.ts

users$: Observable<Object>;

getUsers() {
    this.users$ = this.member.getList();
  }

register.component.html

<ul>
  <ng-container *ngFor="let user of users$ | async ">
    <li>
      {{user | json}}  <-- This gives me a string. If I use {{ user }} without the json pipe, I get an object, but can't reference its properties.
    </li>
  </ng-container>
</ul>

Currently, in my ngFor* loop, I'm unable to grab the user object and reference it's properties (i.e. user.authData[0].username). How can I modify my code to be able to reference user's properties in the template? Do I have to provide the data type in advance to the get call, or is there another way?

EDIT (1): Here is some sample data returned by the {{ user | json }} pipe:

 { "_id": "5cf1b7792ecf136bd4cddebf", "authData": [], "nameData": [], "emailData": [], "phoneData": [], "addressData": [], "companyData": [], "idData": [], "photoData": [], "memberData": [], "creditCardData": [], "__v": 0 }
{ "_id": "5cf207038e3f2551dcf4c803", "authData": [], "nameData": [], "emailData": [], "phoneData": [], "addressData": [], "companyData": [], "idData": [], "photoData": [], "memberData": [], "creditCardData": [], "__v": 0 }
{ "_id": "5d6ff6ac7046a519403c801f", "authData": [], "nameData": [], "emailData": [], "phoneData": [], "addressData": [], "companyData": [], "idData": [], "photoData": [], "memberData": [], "creditCardData": [], "__v": 0 }
{ "_id": "5d7015dddba7384d64540571", "authData": [], "nameData": [], "emailData": [], "phoneData": [], "addressData": [], "companyData": [], "idData": [], "photoData": [], "memberData": [], "creditCardData": [], "__v": 0 }
{ "_id": "5d7061fd767c8c41202f49b7", "authData": [], "nameData": [], "emailData": [], "phoneData": [], "addressData": [], "companyData": [], "idData": [], "photoData": [], "memberData": [], "creditCardData": [], "__v": 0 }
{ "_id": "5d71b9b1fa4fb10afc346323", "authData": [], "nameData": [], "emailData": [], "phoneData": [], "addressData": [], "companyData": [], "idData": [], "photoData": [], "memberData": [], "creditCardData": [], "__v": 0 }
{ "_id": "5d71bcd2fa4fb10afc346332", "authData": [], "nameData": [], "emailData": [], "phoneData": [], "addressData": [], "companyData": [], "idData": [], "photoData": [], "memberData": [], "creditCardData": [], "__v": 0 }
{ "_id": "5d71bf76fa4fb10afc34633e", "authData": [], "nameData": [], "emailData": [], "phoneData": [], "addressData": [], "companyData": [], "idData": [], "photoData": [], "memberData": [], "creditCardData": [], "__v": 0 }
{ "_id": "5d71ce7d52a93e0700f2c052", "authData": [], "nameData": [], "emailData": [], "phoneData": [], "addressData": [], "companyData": [], "idData": [], "photoData": [], "memberData": [], "creditCardData": [], "__v": 0 } 

Upvotes: 0

Views: 213

Answers (3)

Muhammed Albarmavi
Muhammed Albarmavi

Reputation: 24424

base of your data sample you can get the authData data like this

<ul>
    <ng-container *ngFor="let user of users ">
        <li >
            user id {{user._id}} , authData length {{user.authData.length}}
            userName <span *ngFor="let auth of user.authData">  {{auth.userName }}</span>
        </li>
    </ng-container>
</ul>

demo ⚡⚡

Upvotes: 1

Mohamed Sweelam
Mohamed Sweelam

Reputation: 1229

Of course you can; by the way Angular returns the object parsed to you; all you need is to have some object variable that contains the response; generally this object can be of type any, BUT you need first to subscribe to the response.

As an example that simulates some of your json to access it direclty

getUsers() {
    this.member.getList().subscribe( resp => {
         this.users = resp;

         // To go through your json, you can use direct access like the following
         this.users.foreach(user => {
            let id = user['id'];                   // get the id
            let authData: [] = user['authData'];   // get authData list
         });

    })
}

And so on, this will allow you to parse dynamically instead of creating the model again in front-end. and as you have to know to access that from HTML you need to bind each object and replacing my code objects (id & authData) with them . Your code for this part in html after subscribing and assigning the result should work normally, also you can do nested loops without issue.

Upvotes: 1

Dragos Lupei
Dragos Lupei

Reputation: 612

member.service.ts:

getUsers(): Observable<any[]> {
  return this.httpClient
    .get<any[]>(`${environment.api_url}/api/users`)
    .pipe(map(data => data));}

register.component.ts:

  getUsers() {
    this.memberService.getUsers().subscribe(data => {
      this.users = data;
    });
  }

Then use like you wrote

<ul>
  <ng-container *ngFor="let user of users$ | async ">
    <li>
      {{user._id}}  <-- For example user name
    </li>
  </ng-container>
</ul>

Upvotes: 2

Related Questions