Need some help, I am retrieving data from an API but when I try to display the data on my component.html it shows as object object.
I can see the data correctly in the console when it gives me the error: error: cannot find a differ supporting object of type 'string'. ngfor only supports binding to iterables such as arrays.
service.ts:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, forkJoin, map, tap } from 'rxjs';
import { mergeMap } from 'rxjs';
import { Story } from './data';
@Injectable({
providedIn: 'root'
})
export class HackerNewsService {
data: Story[] = [];
constructor(private http: HttpClient) { }
// Get Best Stories ////////////////////////////////////////////////////////////////////////////////
getBestStories() {
return this.listBestStories().pipe(
mergeMap((ids) => forkJoin(ids.map((id: any) => this.getStory(id)))),
map((response: any) => response as Story ),
tap((data: Story) => console.log('Details: Best Stories'))
);
}
getStory(id: any) {
return this.http.get(`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`);
}
listBestStories(): Observable<any> {
return this.http.get('https://hacker-news.firebaseio.com/v0/beststories.json?print=pretty', {
params: {
orderBy: '"$key"',
limitToFirst: '30',
}
});
}
app.component.ts:
import { Component } from '@angular/core';
import { HackerNewsService } from './hacker-news.service';
import { Story } from './data';
import { Subscription } from 'rxjs';
import { Observable } from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Test';
stories: any[] | undefined
subscriptions: Subscription[] = [];
// data: Story | undefined;
data: Story = {
id: '',
deleted: '',
type: '',
by: '',
time: '',
text: '',
dead: '',
parent: '',
poll: '',
kids: '',
url: '',
score: '',
title: '',
parts: '',
descendants: ''
};
constructor(private hnService: HackerNewsService) {}
getStories() {
const start = performance.now();
this.subscriptions.push(
this.hnService.getBestStories()
.subscribe((details: Story) => {this.data = details})
)
}
}
app.component.html:
<button (click)="getStories()">Get Best Stories</button>
<div *ngFor="let item of data | keyvalue">
<ul>
<li>{{item.key}} {{item.value}}</li>
</ul>
</div>
CodePudding user response:
you have a couple of issues
- details is an array, and data is an object here:
this.hnService.getBestStories()
.subscribe((details: Story) => {this.data = details})
- the items of this details array have the shape:
{
by: "georgecmu"
descendants: 374
id: 30108998
kids: Array[33]
score: 1084
time: 1643328979
title: "I won the local election, but my township ignored the results and state law"
type: "story"
url: "https://twitter.com/gaughen/status/1486834885964832770"
}
so it has no "key" and "value" properties
and your template is trying to get this invalid properties:
<li>{{item.key}} {{item.value}}</li>
so the fixes are:
- "data" variable's type should be an array of "Story"
data: Story[] = [{
id: '',
deleted: '',
type: '',
by: '',
time: '',
text: '',
dead: '',
parent: '',
poll: '',
kids: '',
url: '',
score: '',
title: '',
parts: '',
descendants: ''
}];
- the template should be change to use properties present in the
dataitems
<li>{{item.id}} {{item.title}}</li>
here is a working version of your question.
CodePudding user response:
The use the keyvalue pipe, ensure that you have imported it on your component:
import {KeyValue} from '@angular/common':
