Home > Blockchain >  Why does my object keep displaying as object object?
Why does my object keep displaying as object object?

Time:01-29

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

  1. details is an array, and data is an object here:
this.hnService.getBestStories()
        .subscribe((details: Story) => {this.data = details})
  1. 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:

  1. "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: ''
  }];
  1. the template should be change to use properties present in the data items
<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':
  •  Tags:  
  • Related