【问题标题】:http with Observable in Angular 2 cant use dataAngular 2中带有Observable的http不能使用数据
【发布时间】:2017-06-17 03:10:42
【问题描述】:

我是 angular 2 和 observables 的新手,但我想试一试。所以我已经安装了 angular-cli 并做了一个简单的测试项目。

我想要做的只是读取一个 json 文件并处理组件内部的数据(最初的目的是提供服务,但我想从低端开始)。

所以我在 assets/json 文件夹 (testjson.json) 中创建了一个 json 文件:

{
  "teststring": "test works"
}

然后我从我的 content.component.ts 文件中导入了来自 angular 的 http 和 rxjs 地图内容:

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() {

  }

}

到目前为止一切顺利,应用程序打印出以下内容:

app works!

test works [object Object]

但我想在整个组件中使用这些数据,而不仅仅是在构造函数中。但是如果我尝试在构造函数之外(在 ngOnInit 函数内)控制台记录“this.data”,它会在控制台中打印 undefined。

我知道,它一定与异步加载有关,但不幸的是我不知道如何告诉应用程序等到 this.data 被填充。

我希望你能帮助我。当然,将来我想要一种服务,它可以做这种事情,并且不止一个组件应该从中获取数据。

提前致谢!

【问题讨论】:

  • 首先将你的异步代码从构造函数移动到 ngOnInit()。承诺解决后您的数据可用

标签: json angular typescript observable angular-cli


【解决方案1】:
  • 您应该将初始化代码移到初始化方法中。
  • 回调完成后,您的数据将可用。在您的模板中,一旦有数据,您就可以使用*ngIf 在块内执行代码。只要*ngIf 没有评估为真,内部代码就不会运行。
  • 运行console.log(data) 的唯一方法是从回调内部或从回调中调用,因为您必须等到数据加载完毕。

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

编辑

回应下面的评论如果您抽象出对服务的 http 调用,您可以看到完全相同的逻辑仍然适用。您仍在使用数据承诺的概念,并且一旦完成,您就可以订阅该承诺。这里唯一的区别是 http 调用被抽象为不同的类。

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

服务

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

【讨论】:

  • 好的,谢谢,但是 console.log 只是为了快速测试数据是否存在。想象一下我有一个服务,持有 this.data,我想从一个组件调用服务的 getter 来获取该数据并打印出测试字符串。只要异步请求正在运行,getter 就无法传递正确的数据。因此,如果我在组件内部调用 getter,则服务将提供未定义的服务。如何等待服务填充 this.data?
  • @sonnenpriester - 与您现在所做的完全相同。您从您的服务中返回一个 IObservable,它具有数据的承诺,并从您的组件中订阅它。上面的代码和添加服务的唯一区别是抽象了http对服务的调用。
  • @sonnenpriester - 我添加了另一个带有服务的示例。正如您所看到的,这个概念没有改变,您使用做某事的承诺,然后订阅该承诺以在承诺完成时执行某事。
  • 这是否意味着我们对从服务获取数据的每个组件都有一个请求?我的意图是服务发出一个请求并将数据存储在 this.data 中,所有组件只需调用一个 getter 从服务获取存储在 this.data 中的数据。
  • @sonnenpriester - 您可以将数据结果作为变量缓存在服务中。然后组件检查服务中是否存在数据,如果尚未初始化,则以与上面编写代码相同的方式调用方法。
猜你喜欢
  • 2017-02-02
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 2018-01-18
  • 2021-09-26
  • 1970-01-01
  • 1970-01-01
  • 2016-12-12
相关资源
最近更新 更多