0

I'm using Json placeholder. I want to learn how to fetch records from remote server and use it. Here is my code:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-photographs',
  templateUrl: './photographs.component.html',
  styleUrls: ['./photographs.component.css']
})
export class PhotographsComponent implements OnInit {

  myStringifiedJson;

  constructor() {
    console.log(this.myStringifiedJson["title"]);
  }

  ngOnInit() {
    fetch('https://jsonplaceholder.typicode.com/photos')
    .then(response => response.json())
    .then(json => this.myStringifiedJson=JSON.parse(json));
  }
}

I'm getting this error:

ERROR TypeError: this.myStringifiedJson is undefined

Here is the stackblitz. Please correct me. Do I have to use stringify here ?

Tanzeel
  • 4,174
  • 13
  • 57
  • 110

1 Answers1

1

I see multiple issues here

  1. The variable myStringifiedJson is assigned asynchronously. So by the time you're console logging, it isn't assigned any value yet. Hence the undefined error in the console. You could find more info about async data here.

  2. The value returned from the response.json() is already a valid JS object. The JSON.parse() isn't required.

  3. The object returned from https://jsonplaceholder.typicode.com/photos is actually an array. So you can't access the property title directly. You could however use Array#map method to get all the titles as an array.

Try the following

export class PhotographsComponent implements OnInit {
  myStringifiedJson: any;

  constructor() { }

  ngOnInit() {
    fetch('https://jsonplaceholder.typicode.com/photos')
      .then(response => response.json())
      .then(json => {
        this.myStringifiedJson = json;
        console.log(this.myStringifiedJson.map(t => t['title']));    // <-- print here
      });
  }
}

I've updated your Stackblitz


That said I'd recommend you to use Angular's HttpClient to make HTTP requests instead of fetch. It works in tandem with RxJS observables and provides many advantages like combining the response with RxJS operators and functions.

app.module.ts

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports:      [ BrowserModule, FormsModule, HttpClientModule ],
  ...
})
export class AppModule { }

photographs.component.ts

export class PhotographsComponent implements OnInit {
  myStringifiedJson: any;

  constructor(private http: HttpClient) { }

  ngOnInit() {
    this.http.get('https://jsonplaceholder.typicode.com/photos').subscribe(
      response => {
        this.myStringifiedJson = response;
        console.log(this.myStringifiedJson.map(t => t['title']));
      },
      error => { console.log(error); }
    );
  }
}

Working example: Stackblitz

Update: use *ngFor

You need to bind a variable before you could use the index local variable. Also each element of the array is an object, so without the json pipe it'd just render [object Object].

<p *ngFor="let item of myStringifiedJson">
  {{ item | json }}
</p>

Working example: Stackblitz

ruth
  • 29,535
  • 4
  • 30
  • 57
  • Why did you inject `HttpClient` ? I'm asking this because I don't know. Any specific reason or it's just a good practice? – Tanzeel Sep 29 '20 at 18:14
  • 1
    @Tanzeel: That's the standard procedure to use `HttpClient`. It's an [injectable class](https://github.com/angular/angular/blob/10.1.3/packages/common/http/src/client.ts#L99) decorated with `@Injectable`. – ruth Sep 29 '20 at 18:17
  • 1
    @Tanzeel: You need to bind a variable before you could use the `index` local variable. I've updated the answer. – ruth Sep 29 '20 at 18:23
  • I have great respect for people who not only answer the question but explain the solution also. I owe a lot to these kind of people. Wish I could learn more and more. Thanks a lot Michael. :-) – Tanzeel Sep 30 '20 at 04:00