Reputation: 334
I have a component loading a local json file (contains only name) from assets folder.Since HttpClient takes care of formatting data as json, so didn't use map here.
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators'
export type cont= {name: string};
@Component({
selector: 'my-app',
template: `
1st List
<ul>
<li *ngFor="let contact of contacts | async">{{contact.name}}</li>
</ul>
2st List
<ul>
<li *ngFor="let contact of contacts2 | async">{{contact.name}}</li>
</ul>
`
})
export class AppComponent {;
contacts: Observable<cont[]>;
contacts2: Observable<cont[]>;
constructor (http: HttpClient) {
this.contacts = http.get<cont[]>('http://localhost:4200/assets/contacts.json');
setTimeout(() => this.contacts2 = this.contacts, 500);
}
}
Contacts.json
{
"items": [
{ "name": "Mark Twain" },
{ "name": "Sherlock Holmes" }
]
}
Data can be fetched on browser via http://localhost:4200/assets/contacts.json but When I tried to render the same via async pipe I get this error below.Tried many ways to convert observable to Observable<[]> but none passed this scenario. What's wrong here. how json data over httpclient can be converted to Array ? (tried to follow similar posts but none helped)?
Upvotes: 4
Views: 11380
Reputation: 15442
You are trying to iterate over an object:
{
"items": [
{ "name": "Mark Twain" },
{ "name": "Sherlock Holmes" }
]
}
You should iterate over contacts.items
<ul>
<li *ngFor="let contact of (contacts | async)?.items">{{contact.name}}</li>
</ul>
or just use observable map:
const url = 'http://localhost:4200/assets/contacts.json';
this.contacts = http.get<cont[]>(url).pipe(map(data => data.items));
ANOTHER SOLUTION using Symbol.iterator
I am adding it just because it is interesting (in my opinion) approach although not practical in this case.
I can leave iteration over an asynchronous object:
<ul>
<li *ngFor="let contact of contacts | async">{{contact.name}}</li>
</ul>
but I will convert this object to iterable by adding iterable protocol:
const url = 'http://localhost:4200/assets/contacts.json';
this.contacts = http.get<cont[]>(url).pipe(
map((data: any) => {
data[Symbol.iterator] = () => data.items[Symbol.iterator]();
return data;
})
);
The line
data[Symbol.iterator] = () => data.items[Symbol.iterator]()
redirects iteration over the object (which is impossible by default) to iteration over its items
array.
I created a STACKBLITZ demonstrating this
Upvotes: 7
Reputation: 37
this will surely work just define varible correctly
this happens when data json you have in the variable is not in the array format.define variable like this
contacts:[] and store the json from api like this:-
response = http.get<cont[]>('http://localhost:4200/assets/contacts.json');
this.contacts= response.items //array start from items key
<ul>
<li *ngFor="let contact of contacts">{{contact.name}}</li>
</ul>
Upvotes: 0