问题描述
我是 angular 2 和 observables 的新手,但我想试一试.所以我已经安装了 angular-cli 并做了一个简单的测试项目.
我想让它做的就是读取一个 json 文件并处理组件内部的数据(第一个目的是创建一个服务,但我想从一个较低的基础开始).
所以我在 assets/json 文件夹(testjson.json)中创建了一个 json 文件:
{"teststring": "测试有效"}
然后我从我的 content.component.ts 文件中导入了来自 angular 的 http 和 rxjs 映射内容:
import { Component, OnInit } from '@angular/core';从 '@angular/http' 导入 { Http };导入 'rxjs/add/operator/map';@成分({选择器:'应用程序内容',templateUrl: './content.component.html',styleUrls: ['./content.component.css']})导出类 ContentComponent 实现 OnInit {标题:字符串=默认";数据;构造函数(私有 http:Http){http.get('assets/json/testjson.json').map(res => res.json()).subscribe(data => {this.data = data; this.title = data.teststring; 控制台.log(this.data);});}ngOnInit() {}}
到目前为止一切顺利,应用打印出以下内容:
应用程序有效!测试作品 [object Object]
但我想在整个组件中使用这些数据,而不仅仅是在构造函数中.但是如果我尝试在构造函数之外(在 ngOnInit 函数内)控制台.log "this.data",它会在控制台中打印 undefined.
我知道,它一定与异步加载有关,但不幸的是我不知道如何告诉应用程序等待 this.data 被填充.
希望你能帮我解决这个问题.当然,将来我想要一个可以做那种事情的服务,并且不止一个组件应该从中获取数据.
提前致谢!
- 您应该将初始化代码移到初始化方法中.
- 一旦回调完成,您的数据就可用.在您的模板中,一旦有数据,您就可以使用
*ngIf
在块内执行代码.只要*ngIf
不求值为 true,内部代码就不会运行. - 您可以运行
console.log(data)
的唯一方法是从回调内部或从回调中调用,因为您必须等到数据加载完毕.
content.component.html
<span>{{data.teststring}}</span>
content.component.ts
导出类 ContentComponent 实现 OnInit {标题:字符串=默认";数据:任何=空;构造函数(私有 http:Http){}ngOnInit() {this.http.get('assets/json/testjson.json').map(res => res.json()).订阅(数据=> {this.data = 数据;this.title = data.teststring;控制台日志(this.data);});}}
编辑
回应下面的评论 如果您抽象出对服务的 http 调用,您会看到完全相同的逻辑仍然适用.您仍在使用数据承诺的概念,并且您可以在完成后订阅该承诺.这里唯一的区别是 http 调用被抽象为不同的类.
content.component.ts
导出类 ContentComponent 实现 OnInit {标题:字符串=默认";数据:任何=空;//注入服务构造函数(私有内容服务:内容服务){}ngOnInit() {this.contentService.getData().订阅(数据=> {this.data = 数据;this.title = data.teststring;控制台日志(this.data);});}
服务
导出类 ContentService {构造函数(私有 http:Http){}getData(): IObservable{//其中字符串可以是某种定义的类型返回 http.get('assets/json/testjson.json').map(res => res.json() as {teststring:string});}
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!
- 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});
}
这篇关于Angular 2 中带有 Observable 的 http 不能使用数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!