在Angular 1.x中,UI-Router是我的主要工具.通过返回"解析"值的承诺,路由器将在呈现指令之前等待承诺完成.
或者,在Angular 1.x中,null对象不会使模板崩溃 - 所以如果我不介意暂时不完整的渲染,我可以$digest
在promise.then()
填充最初为空的模型对象后使用它进行渲染.
在这两种方法中,如果可能的话,我宁愿等待加载视图,如果无法加载资源,则取消路由导航.这为我节省了"取消导航"的工作.编辑:注意这具体意味着这个问题要求Angular 2期货兼容或最佳实践方法来执行此操作,并要求尽可能避免使用"Elvis操作符"!因此,我没有选择那个答案.
但是,这两种方法都不适用于Angular 2.0.当然,有一个标准的解决方案计划或可用于此.有谁知道它是什么?
@Component() { template: '{{cats.captchans.funniest}}' } export class CatsComponent { public cats: CatsModel; ngOnInit () { this._http.get('/api/v1/cats').subscribe(response => cats = response.json()); } }
以下问题可能反映了相同的问题:加载数据PROMISE后的Angular 2渲染模板.请注意,问题中没有代码或接受的答案.
试试{{model?.person.name}}
这个应该等待模型不是undefined
然后渲染.
Angular 2将此?.
语法称为Elvis运算符.在文档中引用它很难找到,所以这里是它的副本,以防它们更改/移动它:
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为null时,我们的应用程序崩溃了.
我们可以用NgIf来解决这个问题
The null hero's name is {{nullHero.firstName}}或者我们可以尝试使用&&链接属性路径的一部分,因为知道表达式在遇到第一个null时会失效.
The null hero's name is {{nullHero && nullHero.firstName}}
这些方法具有优点,但它们可能很麻烦,尤其是在属性路径很长的情况下.想象一下,在诸如abcd之类的长属性路径中的某处保护null
Angular"Elvis"运算符(?.)是一种更流畅,更方便的方法来防范属性路径中的空值.当它达到第一个空值时,表达式会失效.显示为空白但应用程序不断滚动且没有错误.
The null hero's name is {{nullHero?.firstName}}
它也适用于长属性路径:
a?.b?.c?.d
该套餐@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{ constructor(private backend: Backend) {} resolve( route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable |Promise |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
它会返回一个Observable .subscribe()
.
例:
// 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);
我希望有所帮助.
编辑:角度团队已经发布了@Resolve装饰器.它仍然需要一些澄清,如何工作,但在此之前,我将在这里采取其他人的相关答案,并提供其他来源的链接:
StackOverflow:在Angular2路由中使用Resolve
StackOverflow:GünterZöchbauer的使用示例
解决文档
GitHub上的路由器补丁
RC4 ChangeLog
RC4发布推文
编辑:此答案仅适用于Angular 2 BETA.在此编辑中,未针对Angular 2 RC发布路由器.相反,当使用Angular 2 RC时,请替换为router
with的引用router-deprecated
以继续使用beta路由器.
Angular2-未来的实现方式将通过@Resolve装饰器实现.在那之前,最接近的传真是CanActivate
组件装饰,每个Brandon Roberts.请参阅https://github.com/angular/angular/issues/6611
尽管beta 0不支持向Component提供已解析的值,但它是计划好的,此处还介绍了一种解决方法:在Angular2路由中使用Resolve
可在此处找到beta 1示例:http://run.plnkr.co/BAqA98lphi4rQZAd/#/resolved.它使用非常类似的解决方法,但稍微更准确地使用RouteData
对象而不是RouteParams
.
@CanActivate((to) => { return new Promise((resolve) => { to.routeData.data.user = { name: 'John' }
另请注意,也有用于访问嵌套/父路由为例变通方法"解决"的价值观,以及和其他的功能,你期望,如果你已经使用1.x的UI的路由器.
请注意,您还需要手动注入完成此操作所需的任何服务,因为CanActivate装饰器中当前不提供Angular Injector层次结构.简单地导入一个喷油器会创建一个新的喷油器的实例,而无需访问来自供应商bootstrap()
,所以你可能要存储自举喷射器的应用范围内的副本.布兰登在这个页面上的第二个Plunk链接是一个很好的起点:https://github.com/angular/angular/issues/4112