2

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.

2 Answers 2

2

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}}

Sign up to request clarification or add additional context in comments.

2 Comments

THANK YOU! This worked on first try, been such a struggle for me. Appreciate your time alot. Calling the function with subscribe in the component did the trick!
You are welcome! Yeah, I understand. The async operations is very confusing in the beginning! Added a little more context around this still in my answer, e.g if you need to manipulate data in component somehow upon navigation to page, you need to notice where the data is available in the subscription and where not, thought it can be useful for the future :) Happy coding! :)
1

It's better to return the observable from the service and subscribe to it in the component:

service:

@Injectable()
export class GullkornService {

  constructor(private http:Http) {
  }

  getGullkorn()  {
    // Return the observable here
    return this.http.get('./gk/gullkorn.json')
    .map(res => res.json());
  }

}

component:

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

  ngOnInit() {
  }

}

2 Comments

Thank you! This is how I do it now. But im wondering a new thing, when or how should i unsubscribe to this, or does it happen automatically?
you can subscribe in ngOnInit and unsubscribe in ngOnDestroy

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.