在Angular 1.x中,UI-Router是我的主要工具。通过回复承诺"解决"值,路由器只是等待承诺在呈现指令之前完成。
或者,在Angular 1.x中,null对象不会使模板崩溃 - 所以如果我不介意暂时不完整的渲染,我可以使用$digest
来渲染{{1填充最初为空的模型对象。
在这两种方法中,如果可能的话,我更愿意等待加载视图,如果无法加载资源,则取消路由导航。这为我节省了" un-navigating"的工作。 编辑:请注意,这具体意味着此问题要求使用Angular 2期货兼容或最佳实践方法来执行此操作,并要求避免使用" Elvis运算符"如果可能的话!因此,我没有选择那个答案。
但是,这两种方法都不适用于Angular 2.0。当然,有一个标准的解决方案计划或可用于此。有谁知道它是什么?
promise.then()
以下问题可能反映了同一问题:Angular 2 render template after the PROMISE with data is loaded。请注意,问题中没有代码或接受的答案。
答案 0 :(得分:85)
尝试{{model?.person.name}}
这应该等待模型不是undefined
然后渲染。
Angular 2将此?.
语法称为Elvis operator。在文档中引用它很难找到,所以这里是它的副本,以防它们改变/移动它:
Elvis运算符(?。)和null属性路径
Angular“Elvis”运算符(?。)是一种流畅且方便的方法,可以防止属性路径中的null和undefined值。如果currentHero为null,则保护视图呈现失败。
The current hero's name is {{currentHero?.firstName}}
让我们详细说明问题和这个特殊的解决方案。
当以下数据绑定title属性为null时会发生什么?
The title is {{ title }}
视图仍然呈现但显示的值为空白;我们只看到“标题是”,之后什么都没有。这是合理的行为。至少应用程序不会崩溃。
假设模板表达式涉及属性路径,如下一个示例所示,我们将显示空英雄的firstName。
The null hero's name is {{nullHero.firstName}}
JavaScript抛出空引用错误,Angular也是如此:
TypeError: Cannot read property 'firstName' of null in [null]
更糟糕的是,整个视图都消失了。
如果我们认为英雄财产绝不能为空,我们可以声称这是合理的行为。如果它必须永远不是null而且它是null,那么我们已经编写了一个应该被捕获并修复的编程错误。抛出异常是正确的做法。
另一方面,属性路径中的空值可能会不时出现,特别是当我们知道数据最终会到达时。
当我们等待数据时,视图应该呈现而没有投诉,并且null属性路径应该像title属性一样显示为空白。
不幸的是,当currentHero为空时,我们的应用程序崩溃了。
我们可以使用NgIf来解决这个问题
<!--No hero, div not displayed, no error -->
<div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>
或者我们可以尝试使用&amp;&amp;链接部分属性路径,知道当遇到第一个null时表达式会失效。
The null hero's name is {{nullHero && nullHero.firstName}}
这些方法具有优点,但它们可能很麻烦,尤其是在属性路径很长的情况下。想象一下,在a.b.c.d。
等长属性路径中的某处保护nullAngular“Elvis”运算符(?。)是一种更流畅,更方便的方法来防范属性路径中的空值。当它达到第一个空值时,表达式会失效。显示为空白但应用程序不断滚动,没有错误。
<!-- No hero, no problem! -->
The null hero's name is {{nullHero?.firstName}}
它也适用于长属性路径:
a?.b?.c?.d
答案 1 :(得分:34)
包@angular/router
具有路由的Resolve
属性。因此,您可以在渲染路径视图之前轻松解析数据。
请参阅:https://angular.io/docs/ts/latest/api/router/index/Resolve-interface.html
截至2017年8月28日的文档示例:
class Backend {
fetchTeam(id: string) {
return 'someTeam';
}
}
@Injectable()
class TeamResolver implements Resolve<Team> {
constructor(private backend: Backend) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<any>|Promise<any>|any {
return this.backend.fetchTeam(route.params.id);
}
}
@NgModule({
imports: [
RouterModule.forRoot([
{
path: 'team/:id',
component: TeamCmp,
resolve: {
team: TeamResolver
}
}
])
],
providers: [TeamResolver]
})
class AppModule {}
现在,在解析并返回数据之前,您的路线不会被激活。
访问组件中的已解析数据
要在运行时从组件中访问已解析的数据,有两种方法。因此,根据您的需求,您可以使用:
route.snapshot.paramMap
返回一个字符串,或route.paramMap
返回一个您可以.subscribe()
的Observable。 示例:
// the no-observable method
this.dataYouResolved= this.route.snapshot.paramMap.get('id');
// console.debug(this.licenseNumber);
// or the observable method
this.route.paramMap
.subscribe((params: ParamMap) => {
// console.log(params);
this.dataYouResolved= params.get('id');
return params.get('dataYouResolved');
// return null
});
console.debug(this.dataYouResolved);
我希望有所帮助。
答案 2 :(得分:6)
编辑:此答案仅适用于Angular 2 BETA。在此编辑中,未针对Angular 2 RC发布路由器。相反,在使用Angular 2 RC时,将router
的引用替换为router-deprecated
以继续使用beta路由器。
Angular2-未来的实现方式将通过@Resolve装饰器实现。在此之前,最接近的传真是CanActivate
组件装饰,每个Brandon Roberts。见https://github.com/angular/angular/issues/6611
虽然测试版0不支持向组件提供已解析的值,但它已经过计划,此处还介绍了一种解决方法:Using Resolve In Angular2 Routes
可在此处找到测试版1示例:http://run.plnkr.co/BAqA98lphi4rQZAd/#/resolved。它使用非常类似的解决方法,但使用RouteData
对象而不是RouteParams
稍微更准确一些。
@CanActivate((to) => {
return new Promise((resolve) => {
to.routeData.data.user = { name: 'John' }
另请注意,还有一个示例解决方法,用于访问嵌套/父路由“已解析”值,以及您使用1.x UI-Router时所期望的其他功能。
请注意,您还需要手动注入完成此操作所需的任何服务,因为CanActivate装饰器中当前不提供Angular Injector层次结构。简单地导入Injector将创建一个新的注入器实例,无法访问bootstrap()
的提供者,因此您可能希望存储应用程序范围的自举注入器副本。 Brandon在此页面上的第二个Plunk链接是一个很好的起点:https://github.com/angular/angular/issues/4112
答案 3 :(得分:4)
使用观察者设置本地值
...另外,不要忘记使用虚拟数据初始化值以避免uninitialized
错误。
export class ModelService {
constructor() {
this.mode = new Model();
this._http.get('/api/v1/cats')
.map(res => res.json())
.subscribe(
json => {
this.model = new Model(json);
},
error => console.log(error);
);
}
}
这假设Model是表示数据结构的数据模型。
没有参数的模型应该创建一个新实例,其中所有值都已初始化(但为空)。这样,如果模板在收到数据之前呈现,则不会抛出错误。
理想情况下,如果您希望保留数据以避免不必要的http请求,则应将其放在具有您自己的可以订阅的观察者的对象中。
答案 4 :(得分:2)
在routerOnActivate
中实施@Component
并返回您的承诺:
https://angular.io/docs/ts/latest/api/router/OnActivate-interface.html
编辑:这显然不起作用,虽然目前的文档可能有点难以解释这个主题。有关详细信息,请参阅Brandon的第一条评论:https://github.com/angular/angular/issues/6611
编辑:关于其他通常准确的Auth0网站的相关信息不正确:https://auth0.com/blog/2016/01/25/angular-2-series-part-4-component-router-in-depth/
编辑:角度团队正在为此目的规划一个@Resolve装饰器。
答案 5 :(得分:2)
我发现一个很好的解决方案是在UI上执行以下操作:
<div *ngIf="vendorServicePricing && quantityPricing && service">
...Your page...
</div
仅在加载vendorServicePricing
,quantityPricing
和service
时才会呈现页面。