Angular2:在渲染组件之前如何加载数据?
Angular2:在渲染组件之前如何加载数据?
在组件渲染之前,我正在尝试从我的API中加载一个事件。目前,我正在使用我的API服务,我从组件的ngOnInit函数中调用它。
我的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); // 有值 console.log(this.ev); // 有值 }); } ngOnInit() { this.fetchEvent(); console.log(this.ev); // 没有值 } }
我的EventRegister
模板:
Hi this sentence is always visible, even if `ev property` is not loaded yet I should be visible as soon the `ev property` is loaded. Currently I am never shown. {{event.id }}
我的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=> { return this.http.get("api/events/" + eventId).map(response => { return response.json(); // 有值 }).toPromise(); } } }
组件在ngOnInit
函数中的API调用完成之前就被渲染了。所以我从视图模板中无法看到事件ID。看起来像是一个异步问题。我期望在设置ev
(EventRegister
组件)属性之后,绑定会做一些工作。可惜当属性被设置时,它不会显示带有*ngIf="ev"
标记的div
。
问题:我使用的方法好吗?如果不好,加载数据在组件开始渲染之前的最佳方法是什么?
注意:在这个angular2教程中使用了ngOnInit
方法。
编辑:
两个可能的解决方案。第一个是放弃fetchEvent
,只在ngOnInit
函数中使用API服务。
ngOnInit() { this._apiService.get.event(this.eventId).then(event => this.ev = event); }
第二个解决方案,就像给出的答案一样。
fetchEvent(): Promise{ return this._apiService.get.event(this.eventId); } ngOnInit() { this.fetchEvent().then(event => this.ev = event); }
Angular2: 如何在渲染组件之前加载数据?
在Angular2+中,您可以使用解析器(Resolvers)来预取数据,解析器能在组件完全加载之前处理数据。有许多情况下,您只想在发生某些特定事件时加载组件,例如只有在用户已登录时导航到仪表板,这种情况下解析器非常方便。下面是我为您创建的一个简单图表,展示了如何使用解析器将数据发送到组件。
![enter image description here](https://i.stack.imgur.com/eHzu2.jpg)
将解析器应用到您的代码中非常简单,我为您创建了代码片段,以便查看如何创建解析器:
import { Injectable } from '/core'; import { Router, Resolve, RouterStateSnapshot, ActivatedRouteSnapshot } from '/router'; import { MyData, MyService } from './my.service'; @Injectable() export class MyResolver implements Resolve{ constructor(private ms: MyService, private router: Router) {} resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { 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; }); }
在路由中(通常在app.routing.ts文件中)可以这样配置:
{path: 'yourpath/:id', component: YourComponent, resolve: { myData: MyResolver}}
我认为您错过了在路由配置的Routes数组中添加条目(通常在app.routing.ts文件中):{path: 'yourpath/:id', component: YourComponent, resolve: { myData: MyData}}
,这不应该覆盖所有部分,但我同意,这样回答更全面,所以我添加了... 谢谢。
请纠正最后一部分,路由中的resolve参数应该指向解析器本身,而不是数据类型,即resolve: { myData: MyResolver }
。
MyData是在MyService中定义的模型对象吗?
这个解决方案适用于在页面加载之前获取数据,但不适用于检查已登录的用户或用户角色。对于这种情况,您应该使用守卫(Guards)。
在Angular 2中,有一个常见的问题是在组件渲染之前如何加载数据。在本文中,我们将讨论这个问题的原因以及解决方法。
问题的原因是Angular的单向数据流规则禁止在组件视图组合之后更新视图。这意味着我们不能在视图渲染之前加载数据。在Angular 1中,有一个解决方法是在UI上使用条件渲染。只有当isDataLoaded为true时,页面才会被渲染。然而,这个解决方法在Angular 2及以上版本中不再适用。
解决方法是使用变化检测策略(ChangeDetectionStrategy)来实现双向绑定。默认情况下,Angular使用的是ChangeDetectionStrategy.Default。我们可以将其更改为ChangeDetectionStrategy.Push,以实现双向绑定。这样,数据加载完成后,页面会自动更新并渲染。
这个解决方法已经在Angular 6中得到验证,可以正常工作。现在,我们可以在组件渲染之前加载数据,并在加载完成后更新页面。
总结起来,解决这个问题的方法是使用变化检测策略来实现双向绑定。通过将ChangeDetectionStrategy设置为Push,可以在组件渲染之前加载数据,并在加载完成后自动更新页面。这个解决方法已经在Angular 6中得到验证,并且可以成功解决问题。
在Angular2中,有时候我们需要在组件渲染之前加载数据。在这个问题中,问题的原因是在调用this.fetchEvent()
之后立即执行console.log(this.ev)
语句时,fetchEvent()
方法并没有执行完成,只是被调度了,因此console.log(this.ev)
语句并没有得到正确的值。
解决方法是将fetchEvent()
方法改为返回一个Promise
对象,并在ngOnInit()
方法中等待Promise
对象完成。这样可以确保在组件渲染之前数据已经加载完毕。
另外,可以在模板中使用*ngIf
指令来包裹整个模板内容,只有在数据加载完成后才显示模板内容。
总结起来,解决这个问题的方法有两种:
1. 将fetchEvent()
方法改为返回Promise
对象,并在ngOnInit()
方法中等待Promise
对象完成。
2. 使用*ngIf
指令在模板中判断数据是否加载完成,只有在数据加载完成后才显示模板内容。
在这个问题中,使用第一种方法解决了问题,并得到了满意的结果。不过,有人认为这种方法只是一个权宜之计,而不是一个正确的解决方案。在Angular 5中应该有更好的解决方法。
对此,有人表示不理解为什么会有人对这种解决方法提出异议,认为这两种方法都是完全可以接受的。
总之,从这个问题中可以看出,为了在组件渲染之前加载数据,可以使用返回Promise
对象的方法或者使用*ngIf
指令来判断数据是否加载完成。