Angular2:如何在渲染组件之前加载数据? [英] Angular2: How to load data before rendering the component?
问题描述
我正在尝试在呈现组件之前从我的 API 加载事件.目前我正在使用我从组件的 ngOnInit 函数调用的 API 服务.
我的EventRegister
组件:
import {Component, OnInit, ElementRef} from "angular2/core";从../../services/api.service"导入{ApiService};从'../../models/EventModel'导入{EventModel};从 'angular2/router' 导入 {Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig, RouteParams, RouterLink};从'angular2/common'导入{FORM_PROVIDERS, FORM_DIRECTIVES, Control};@成分({选择器:注册",templateUrl: "/events/register"//提供者数组添加到父组件中})导出类 EventRegister 实现 OnInit {事件 ID:字符串;ev:事件模型;构造函数(私有_apiService:ApiService,参数:RouteParams) {this.eventId = params.get('id');}fetchEvent(): 无效 {this._apiService.get.event(this.eventId).then(event => {this.ev = 事件;控制台日志(事件);//有一个值控制台日志(this.ev);//有一个值});}ngOnInit() {this.fetchEvent();控制台日志(this.ev);//没有价值}}
我的EventRegister
模板
嗨这句话总是可见的,即使`ev property`尚未加载<div *ngIf="ev">一旦加载了ev 属性",我就应该可见.目前我从未出现过.<span>{{event.id }}</span>
注册>
我的 API 服务
import "rxjs/Rx"从angular2/http"导入{Http};从angular2/core"导入{Injectable};从'../models/EventModel'导入{EventModel};@Injectable()导出类 ApiService {构造函数(私有http:Http){}得到 = {事件: (eventId: string): Promise=>{return this.http.get("api/events/" + eventId).map(response => {返回 response.json();//有一个值}).承诺();}}}
组件在 ngOnInit
函数中的 API 调用完成获取数据之前被渲染.所以我永远不会在我的视图模板中看到事件 ID.所以看起来这是一个 ASYNC 问题.我希望 ev
(EventRegister
组件)的绑定在 ev
属性设置后做一些工作.遗憾的是,当属性被设置时,它没有显示用 *ngIf="ev"
标记的 div
.
问题:我使用了一个好的方法吗?如果不;在组件开始呈现之前加载数据的最佳方式是什么?
注意: ngOnInit
方法用于此 angular2 教程.
两种可能的解决方案.首先是放弃 fetchEvent
并只使用 ngOnInit
函数中的 API 服务.
ngOnInit() {this._apiService.get.event(this.eventId).then(event => this.ev = event);}
第二种解决方案.就像给出的答案一样.
fetchEvent(): Promise{返回 this._apiService.get.event(this.eventId);}ngOnInit() {this.fetchEvent().then(event => this.ev = event);}
更新
如果您使用路由器,您可以使用生命周期钩子或解析器来延迟导航,直到数据到达.https://angular.io/guide/router#milestone-5-route-guards
在根组件初始渲染之前加载数据
APP_INITIALIZER
可以使用 如何将后端渲染的参数传递给angular2 bootstrap方法
原创
当 console.log(this.ev)
在 this.fetchEvent();
之后执行时,这并不意味着 fetchEvent()
code> call is done,这只意味着它被安排了.当 console.log(this.ev)
被执行时,甚至没有调用服务器,当然还没有返回值.
更改 fetchEvent()
以返回一个 Promise
fetchEvent(){返回 this._apiService.get.event(this.eventId).then(event => {this.ev = 事件;控制台日志(事件);//有一个值控制台日志(this.ev);//有一个值});}
更改 ngOnInit()
等待 Promise
完成
ngOnInit() {this.fetchEvent().then(() =>console.log(this.ev));//现在有值了;}
对于您的用例,这实际上不会给您带来太多好处.
我的建议:将整个模板包装在 <div *ngIf="isDataAvailable>>(模板内容)
和在 ngOnInit()
isDataAvailable:boolean = false;ngOnInit() {this.fetchEvent().then(() =>this.isDataAvailable = true);//现在有值了;}
I am trying to load an event from my API before the component gets rendered. Currently I am using my API service which I call from the ngOnInit function of the component.
My EventRegister
component:
import {Component, OnInit, ElementRef} from "angular2/core";
import {ApiService} from "../../services/api.service";
import {EventModel} from '../../models/EventModel';
import {Router, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, RouteConfig, RouteParams, RouterLink} from 'angular2/router';
import {FORM_PROVIDERS, FORM_DIRECTIVES, Control} from 'angular2/common';
@Component({
selector: "register",
templateUrl: "/events/register"
// provider array is added in parent component
})
export class EventRegister implements OnInit {
eventId: string;
ev: EventModel;
constructor(private _apiService: ApiService,
params: RouteParams) {
this.eventId = params.get('id');
}
fetchEvent(): void {
this._apiService.get.event(this.eventId).then(event => {
this.ev = event;
console.log(event); // Has a value
console.log(this.ev); // Has a value
});
}
ngOnInit() {
this.fetchEvent();
console.log(this.ev); // Has NO value
}
}
My EventRegister
template
<register>
Hi this sentence is always visible, even if `ev property` is not loaded yet
<div *ngIf="ev">
I should be visible as soon the `ev property` is loaded. Currently I am never shown.
<span>{{event.id }}</span>
</div>
</register>
My API service
import "rxjs/Rx"
import {Http} from "angular2/http";
import {Injectable} from "angular2/core";
import {EventModel} from '../models/EventModel';
@Injectable()
export class ApiService {
constructor(private http: Http) { }
get = {
event: (eventId: string): Promise<EventModel> => {
return this.http.get("api/events/" + eventId).map(response => {
return response.json(); // Has a value
}).toPromise();
}
}
}
The component gets rendered before the API call in the ngOnInit
function is done fetching the data. So I never get to see the event id in my view template. So it looks like this is a ASYNC problem. I expected the binding of the ev
(EventRegister
component) to do some work after the ev
property was set. Sadly it does not show the div
marked with *ngIf="ev"
when the property gets set.
Question: Am I using a good approach? If not; What is the best way to load data before the component is starting to render?
NOTE: The ngOnInit
approach is used in this angular2 tutorial.
EDIT:
Two possible solutions. First was to ditch the fetchEvent
and just use the API service in the ngOnInit
function.
ngOnInit() {
this._apiService.get.event(this.eventId).then(event => this.ev = event);
}
Second solution. Like the answer given.
fetchEvent(): Promise<EventModel> {
return this._apiService.get.event(this.eventId);
}
ngOnInit() {
this.fetchEvent().then(event => this.ev = event);
}
update
If you use the router you can use lifecycle hooks or resolvers to delay navigation until the data arrived. https://angular.io/guide/router#milestone-5-route-guards
To load data before the initial rendering of the root component
APP_INITIALIZER
can be used How to pass parameters rendered from backend to angular2 bootstrap method
original
When console.log(this.ev)
is executed after this.fetchEvent();
, this doesn't mean the fetchEvent()
call is done, this only means that it is scheduled. When console.log(this.ev)
is executed, the call to the server is not even made and of course has not yet returned a value.
Change fetchEvent()
to return a Promise
fetchEvent(){
return this._apiService.get.event(this.eventId).then(event => {
this.ev = event;
console.log(event); // Has a value
console.log(this.ev); // Has a value
});
}
change ngOnInit()
to wait for the Promise
to complete
ngOnInit() {
this.fetchEvent().then(() =>
console.log(this.ev)); // Now has value;
}
This actually won't buy you much for your use case.
My suggestion: Wrap your entire template in an <div *ngIf="isDataAvailable"> (template content) </div>
and in ngOnInit()
isDataAvailable:boolean = false;
ngOnInit() {
this.fetchEvent().then(() =>
this.isDataAvailable = true); // Now has value;
}
这篇关于Angular2:如何在渲染组件之前加载数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!