Anurag-Sharma
Anurag-Sharma

Reputation: 4418

Unable to store fetched json data from external server

I am trying to fetch some json data from an external server using the following code:

  ionViewDidLoad(){
    console.log("user-detail page loaded");
  }

  fetchData(){
    let loadingPopup = this.loadingCtrl.create({
      content: 'Please wait...'
    });

    loadingPopup.present();

    let user_data = "";
    this.url = this.navParams.get("url");

    return new Promise(resolve => {
      this.http.post(this.url, null)
        .subscribe(data => {
          resolve( data );
          loadingPopup.dismiss();
        });
    });
  }

  ionViewDidEnter(){
    this.fetchData().then(data => {
      this.user = JSON.parse(data._body);
    });
    console.log(this.user);
  }

The output of the console.log(this.user) is undefined. I wanted to know where I am going wrong.

Upvotes: 1

Views: 54

Answers (1)

Michael Doye
Michael Doye

Reputation: 8171

That behavior is expected, since you have to wait for the HTTP response to be returned from the server. As I am sure you know, Promises and Observables are Asynchronous, so in your example, the rest of your code will still be executed while you are waiting for a response from the server.

Just because it is undefined in your controller during that lifecylcle hook does not necessarily mean you cant access it from your view. However to prevent errors stemming from your view, you can use ngIf in your view to make sure the data is there before a particular element is loaded:

<p *ngIf="user">{{ user.displayName}}</p> 

You can also use the safe navigation operator (?):

<p>{{ user?.displayName}}</p> 

As as a side note, I would recommend sticking to either promises or observables for your HTTP requests as I see you are combining the two. You might also consider moving your HTTP requests into a separate service file and then injecting that service into your controller. This pattern helps to keep the code manageable as your application starts to grow. Here is an example of such a pattern based on your code:

api.service.ts

import { Http } from '@angular/http';
import { Injectable } from '@angular/core';
import { Observable } from "rxjs/Observable";
import 'rxjs/add/operator/map';

@Injectable()
export class ApiService {

  constructor(private http: Http) {}

  fetchData(url: string): Observable<any> {
    return this.http.get(url)
      .map(data => data.json());
  }
}

your.comonent.ts

  constructor(private api: ApiService, private loadingCtrl: LoadingController) { 
    console.group('LifeCycle'); 
  }

  ionViewDidLoad() {
    // will be undefined
    console.log("ionViewDidLoad", this.launch);
  }

  ionViewDidEnter() {
    this.fetchDataFromService();
    // will be undefined
    console.log('ionViewDidEnter', this.launch);
  }

  fetchDataFromService() {
    let loadingPopup = this.loadingCtrl.create({
      content: 'Please wait...'
    });
    loadingPopup.present();

    //let user_data = "";
    this.url = 'https://api.spacexdata.com/v2/launches/latest';

    this.api.fetchData(this.url).subscribe(data => {
      console.log('Server Response', data);
      this.launch = data;
      loadingPopup.dismiss();
    },
    (e:Error) => console.log(e));
  }

StackBlitz

Upvotes: 1

Related Questions