Search code examples
angularangular2-services

How to extract JSON data from http.get in Angular 2 properly?


I can't seem to manage to make a variable for the view with the info from a json file but I'm so close. I can echo out the information in the .subscribe()-chain, but it won't set it to a variable, they just get undefined, what am I doing wrong?

I just want to load my json file into a variable in the component view. It was easy in Angular 1.

My service:

import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/map';
import {Observable} from 'rxjs/Rx';

@Injectable()
export class GullkornService { 
result: any;

constructor(private http:Http) {
}

getGullkorn()  {

let result = this.result;
this.http.get('./gk/gullkorn.json')
.map(res => res.json())
.subscribe(
        val => this.result = val,
        err => console.error(err),
        () =>  console.log(this.result));  // this one echoes out what i want
        console.log(this.result); // but this one doesnt, so i cant return it 
      }
}

And the landing component:

import { Component, OnInit } from '@angular/core';
import {Router, RouterOutlet} from '@angular/router';
import { HttpModule, JsonpModule } from '@angular/http';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule }      from '@angular/core';
import { GullkornService } from '../../gullkorn-service.service';
import { FormsModule }   from '@angular/forms';
import {Observable} from 'rxjs/Observable';

import "gsap";
declare var ease, TimelineMax,TweenMax,Power4,Power1,Power2,Power3,Bounce, Elastic:any;

@Component({
  selector: 'gullkorn-visning',
  providers: [GullkornService],
  templateUrl: './landing.component.html',
  styleUrls: ['./landing.component.css']
})
export class LandingComponent implements OnInit {
  gullkorn: any;
  constructor(GullkornService: GullkornService) { 
        this.gullkorn = GullkornService.getGullkorn();
        console.log(this.gullkorn);
  }

  ngOnInit() {
  }

}

Based on current code this is what I get:

result

I have the project here: github.


Solution

  • This is an async operation, so when you try to console.log the result it's undefined, as it is being run before the other console.log inside the subscription.

    .subscribe(
            val => this.result = val,
            err => console.error(err),
            () =>  console.log(this.result));  // is run sometimes later
            console.log(this.result); // is run first
          }
    

    I would make some changes to your code... I would suggest you take care of the subscription in the component instead, this would be the best way to handle http-requests. So just map in the service and return the observable to the component, remember to add return statement :

    getGullkorn() {
      return this.http.get('./gk/gullkorn.json')
        .map(res => res.json())
    }
    

    In your component I would suggest you move your service call in OnInit instead. Here you can also notice that the values aren't instantly accessible outside the subscription as per comments in code. So if you want to manipulate your data somehow, you need to take that into consideration :)

    ngOnInit() {
      this.GullkornService.getGullkorn()
        .subscribe(data => {
         // is run sometimes later
         this.gullkorn = data
      });
      // is run first
    }
    

    AS this is an async operation, so be prepared to use either ngIf or the safe navigation operator in your view, since view is rendered before data has been retrieved.

    So either wrap your code inside ngIf:

    <div *ngIf="gullkorn"></div>
    

    or {{gullkorn?.someProperty}}