Angular 2中带有Observable的http不能使用数据

Posted

技术标签:

【中文标题】Angular 2中带有Observable的http不能使用数据【英文标题】:http with Observable in Angular 2 cant use data 【发布时间】: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()。承诺解决后您的数据可用 【参考方案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 - 您可以将数据结果作为变量缓存在服务中。然后组件检查服务中是否存在数据,如果尚未初始化,则以与上面编写代码相同的方式调用方法。

以上是关于Angular 2中带有Observable的http不能使用数据的主要内容,如果未能解决你的问题,请参考以下文章

在 Angular 2 中对 observable 进行单元测试

Angular 2 - 直接从 Observable 返回数据

Angular 2 - 路由 - CanActivate 与 Observable 一起工作

具有多个订阅者的 Angular 2 Observable

在这个 Angular 2 示例中,这种 Observable 行为究竟是如何工作的?

Angular 2 - Observable 中的排序列表