Angular2:如何在渲染组件之前加载数据?

我正试图从我的API加载一个事件之前组件呈现。 目前,我正在使用我从组件的ngOnInit函数调用的API服务。

我的EventRegister组件:

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

我的EventRegister模板

 <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> 

我的API服务

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

ngOnInit函数的API调用完成获取数据之前,组件被渲染。 所以我从来没有看到我的视图模板中的事件ID。 所以看起来这是一个ASYNC问题。 我期望evEventRegister组件)的绑定在ev属性设置之后做一些工作。 可悲的是,当属性被设置时,它不显示用*ngIf="ev"标记的div

问题:我使用了一个好的方法吗? 如果不; 在组件开始呈现之前加载数据的最佳方式是什么?

注意:在这个angular2教程中使用ngOnInit方法。

编辑:

两种可能的解决 首先是fetchEvent并在ngOnInit函数中使用API​​服务。

 ngOnInit() { this._apiService.get.event(this.eventId).then(event => this.ev = event); } 

第二种scheme 就像给出的答案一样。

 fetchEvent(): Promise<EventModel> { return this._apiService.get.event(this.eventId); } ngOnInit() { this.fetchEvent().then(event => this.ev = event); } 

更新

  • 如果您使用路由器,则可以使用生命周期挂钩或parsing器来延迟导航,直到数据到达。 https://angular.io/docs/ts/latest/guide/router.html#!#guards

  • 可以使用根组件APP_INITIALIZER的初始渲染之前加载数据如何将从后端呈现的parameter passing给angular2引导方法

原版的

console.log(this.ev)this.fetchEvent();之后执行时this.fetchEvent(); ,这并不意味着fetchEvent()调用完成,这只意味着它被调度。 当执行console.log(this.ev) ,对服务器的调用甚至没有进行,当然还没有返回值。

更改fetchEvent()以返回一个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 }); } 

改变ngOnInit()等待Promise完成

 ngOnInit() { this.fetchEvent().then(() => console.log(this.ev)); // Now has value; } 

这实际上不会为你的用例买太多东西。

我的build议:将你的整个模板包装在一个<div *ngIf="isDataAvailable"> (template content) </div>

ngOnInit()

 isDataAvailable:boolean = false; ngOnInit() { this.fetchEvent().then(() => this.isDataAvailable = true); // Now has value; } 

我发现一个很好的解决scheme就是在UI上做这样的事情:

 <div *ngIf="isDataLoaded"> ...Your page... </div 

只有在:isDataLoaded为true时才会呈现页面。

您可以使用Angular2 +中的Resolvers预取数据,parsing器在您的组件完全加载之前处理您的数据。

有很多情况下,只有在某些事情发生时才要加载组件,例如只有在已经login的人员的情况下才能导航到Dashboard,在这种情况下,Resolver非常方便。

看看我为您创build的简单图表,您可以使用parsing器将数据发送到组件。

在这里输入图像描述

parsing器应用于您的代码非常简单,我为您创build了片段,以了解如何创buildparsing器:

 import { Injectable } from '@angular/core'; import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '@angular/router'; import { MyData, MyService } from './my.service'; @Injectable() export class MyResolver implements Resolve<MyData> { constructor(private ms: MyService, private router: Router) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<MyData> { let id = route.params['id']; return this.ms.getId(id).then(data => { if (data) { return data; } else { this.router.navigate(['/login']); return; } }); } } 

并在模块中

 import { MyResolver } from './my-resolver.service'; @NgModule({ imports: [ RouterModule.forChild(myRoutes) ], exports: [ RouterModule ], providers: [ MyResolver ] }) export class MyModule { } 

你可以像这样在你的组件中访问它:

 ///// ngOnInit() { this.route.data .subscribe((data: { mydata: myData }) => { this.id = data.mydata.id; }); } /////