http with Observable in Angular 2 cant use data

2019-02-20 16:17发布

问题:

i am new to angular 2 and to observables but i wanted to give it a shot. So i have installed the angular-cli and made a simple test project.

All i wanted it to do is read a json file and work with the data inside of a component (the first intention was to make a service but i wanted to start on a low basis).

So i have created a json file in the assets/json folder (testjson.json):

{
  "teststring": "test works"
}

then i have imported the http from angular and the rxjs map stuff inside of my content.component.ts file:

import { Component, OnInit } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';

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

  title: string = "Default";
  data;

  constructor(private http:Http) {
    http.get('assets/json/testjson.json').map(res => res.json()).subscribe(data => {this.data = data; this.title = data.teststring; console.log(this.data);});
  }

  ngOnInit() {

  }

}

So far so good, the app prints out the following:

app works!

test works [object Object]

But i want to use this data in the whole component, not only in the constructor. but if i try to console.log "this.data" outside of the constructor (inside the ngOnInit function), it prints undefined in the console.

I know, that it must have something to do with asynch loading but unfortunately i have no clue how to tell the app to wait until this.data is filled.

I hope you can help me with that. Of course in the future i want a service which does that kind of stuff and more than one component should grab data from it.

Thanks in advance!

回答1:

  • You should move the initialization code to the initialization method.
  • Your data becomes available once the callback completes. In your template you can use *ngIf to execute code inside a block once there is data. As long as the *ngIf does not eval to true the inner code will not run.
  • The only way you can run console.log(data) is from inside the callback or called from the callback because you have to wait until the data is loaded.

content.component.html

<div *ngIf="data">
  <span>{{data.teststring}}</span>
</div>

content.component.ts

export class ContentComponent implements OnInit {

  title: string = "Default";
  data: any = null;

  constructor(private http:Http) {
  }

  ngOnInit() {
    this.http.get('assets/json/testjson.json')
      .map(res => res.json())
      .subscribe(data => {
        this.data = data;
        this.title = data.teststring;
        console.log(this.data);
      });
  }
}

Edit

In response to the comment below If you abstract out the http call to a service you can see the exact same logic still applies. You are still using the concept of a promise of data and that you can subscribe to that promise once it has completed. The only difference here is the http call is abstracted to a different class.

content.component.ts

export class ContentComponent implements OnInit {

  title: string = "Default";
  data: any = null;

  // inject service
  constructor(private contentService:ContentService) {
  }

  ngOnInit() {
    this.contentService.getData()
      .subscribe(data => {
        this.data = data;
        this.title = data.teststring;
        console.log(this.data);
      });
  }

Service

export class ContentService {

  constructor(private http:Http) {
  }

  getData(): IObservable<{teststring:string}> { // where string can be some defined type
    return http.get('assets/json/testjson.json')
      .map(res => res.json() as {teststring:string});
  }