Search code examples
angulartypescriptobservableangular-services

How to read JSON response from a REST API using Angular


I'm learning Angular basics. I've picked up a very small project. I'm using JSONPlaceholder, the fake REST API. I want to read all posts and render them on a the page using simple ngFor loop. I've created a service for that. I'll show my code one by one. But here's the stackblitz for the same. I need help with these files only:

  1. post-list
  2. post interface
  3. post.service

I've written this much code from the scratch after reading atricles and watching tutorials on pluralsight and youtube but now I'm blocked. Here's my code:

post.ts

export interface Post {
  userId: number;
  id: number;
  title: string;
  body: string;
}

post.service.ts

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class PostService {

  constructor() {}

  getAllPosts():Observable<Post[]> {
    return fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(json => console.log(json))
  }
}

post-list.component.ts

import { PostService } from './post.service';
import { Component } from '@angular/core';

import { Post } from './post'

@Component({
  templateUrl: './post-list.component.html',
})
export class PostList {

  posts: Post[] = [];
  errorMessage="";
  
  constructor(private postservice: PostService) {
    this.postservice.getAllPosts().subscribe({
      next: posts => {
        this.posts=posts;
      },
      error: err => this.errorMessage = err
    });
  }
}

I insist, please look at the stackblitz it will save everyone's time and efforts. My problems are:

Can't bind to 'ngForOf' since it isn't a known property of 'div'. ("

Error: 0.9.1/dist/zone.j

Please point out my mistakes and correct me.


Solution

  • First you should change your service and use HttpClient inside HttpClientModule.

    export class PostService {
    
      constructor(private httpClient: HttpClient) {};
    
      getAllPosts(): Observable<Post[]> {
        return this.httpClient.get<Post[]>('https://jsonplaceholder.typicode.com/posts');
      }
    }
    

    Becareful also to correctly import HttpClientModule, and CommonModule is you're using child modules. Common directives, like async won't be accessible if you don't import it.

    @NgModule({
      imports:[
        CommonModule,
        HttpClientModule,
       ...
    

    Then you have multiple options to retrieve and render your result, here are 2 main alternatives :

    Option 1

    @Component({
      templateUrl: './post-list.component.html',
    })
    export class PostList {
      posts: Post[] = [];
      errorMessage: string;
    
      constructor(private postService: PostService) {}
    
      ngOnInit() {
        this.posts = this.postService.getAllPosts().subscribe(
          posts => {
            this.posts = posts
          },
          error => {
            this.errorMessage = error;
          }
        );
      }
    }
    

    Option 2 (recommended)

    @Component({
      templateUrl: './post-list.component.html',
    })
    export class PostList {
      posts$: Observable<Post[]>;
      errorMessage: string;
    
      constructor(private postService: PostService) {}
    
      ngOnInit() {
        this.posts$ = this.postService.getAllPosts().pipe(
          catchError(error => {
            this.errorMessage = error;
          });
        );
      }
    }
    

    template.html :

    <div *ngFor="let post of posts$ | async">
      <p>{{ post.userId }}</p>
      ...
    </div>
    

    See updated stackblitz demo for this recommended option with Observable and async pipe.