提问者:小点点

在渲染视图/模板之前等待Angular 2加载/解析模型


在Angular 1. x中,UI路由器是我的主要工具。通过返回“解析”值的promise,路由器只需等待promise完成后再呈现指令。

或者,在Angular 1. x中,空对象不会使模板崩溃——所以如果我不介意暂时不完整的渲染,我可以在promise之后使用$digest进行渲染。然后()填充一个最初为空的模型对象。

在这两种方法中,如果可能的话,我更愿意等待加载视图,如果无法加载资源,则取消路线导航。这为我节省了“取消导航”的工作。编辑:请注意,这特别意味着这个问题要求一个与Angular 2期货兼容或最佳实践的方法来做到这一点,并要求尽可能避免“埃尔维斯运算符”!因此,我没有选择那个答案。

然而,这两种方法都不适用于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渲染模板。请注意,问题中没有代码或公认的答案。


共3个答案

匿名用户

尝试{{model?。person.name}}这应该等待模型不是undede,然后渲染。

Angular 2引用这个?.语法作为埃尔维斯运算符。在留档中引用它很难找到,所以这里是它的副本,以防他们更改/移动它:

埃尔维斯运算符 ( ?. ) 和空属性路径

Angular"埃尔维斯"运算符 ( ?. ) 是一种流畅方便的方法来防止属性路径中的null和未定义值。在这里,如果当前Hero为null,则防止视图渲染失败。

当前英雄的名字是{{当前英雄?. firstName}}

让我们详细说明这个问题和这个特定的解决方案。

当以下数据绑定标题属性为空时会发生什么?

标题是{{title}}

视图仍然呈现,但显示的值是空白的;我们只看到“标题是”,后面什么都没有。这是合理的行为。至少应用程序不会崩溃。

假设模板表达式涉及一个属性路径,如下一个示例所示,我们将在其中显示空英雄的firstName。

空英雄的名字是{{nullHero. firstName}}

JavaScript抛出空引用错误,Angular也是如此:

TypeError:无法读取[null]中null的属性'firstName'

更糟糕的是,整个视图消失了。

我们可以声称这是合理的行为,如果我们相信英雄属性永远不能为空。如果它永远不能为空,但它是空的,我们就犯了一个应该被捕获和修复的编程错误。抛出异常是正确的做法。

另一方面,属性路径中的空值有时可能没问题,尤其是当我们知道数据最终会到达时。

当我们等待数据时,视图应该毫无怨言地呈现,并且空属性路径应该像title属性一样显示为空白。

不幸的是,当当前的Hero为空时,我们的应用程序会崩溃。

我们可以用NgIF来解决这个问题

或者我们可以尝试将部分属性路径与

空英雄的名字是{{nullHero

这些方法有优点,但它们可能很麻烦,尤其是在属性路径很长的情况下。想象一下在长属性路径(例如a. b.c.d)中的某个地方防止空。

Angular"埃尔维斯"运算符 ( ?. ) 是一种更流畅、更方便的方法来防止属性路径中的空值。表达式在命中第一个空值时退出。显示是空白的,但应用程序一直在滚动,没有错误。

它也适用于长属性路径:

a?。b?。c?。d

匿名用户

@角/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 {}

现在,在解析并返回数据之前,您的路由将不会被激活。

访问组件中已解析的数据

要在运行时从组件内访问解析的数据,有两种方法。因此,根据您的需要,您可以使用以下任一方法:

  1. route. snapshot.para Map返回字符串,或
  2. route. ParamMap它返回一个可观察的对象,您可以。订阅()

示例:

  // 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ünter Zöchbauer的使用示例
  • 解决留档
  • GitHub上的路由器补丁
  • RC4更改日志
  • RC4发布推文

编辑:此答案仅适用于Angular 2 BETA。截至本次编辑,Angular 2RC尚未发布路由器。相反,当使用Angular 2RC时,将对router的引用替换为router-debrecated以继续使用beta路由器。

Angular2-未来实现这一点的方法将是通过@Resolve装饰器。在那之前,最接近的传真是CanActivate组件装饰器,根据Brandon Roberts。见https://github.com/angular/angular/issues/6611

虽然beta0不支持向组件提供解析值,但它是计划中的,这里还描述了一个解决方法:在Angular2路由中使用解析

一个beta1的例子可以在这里找到:http://run.plnkr.co/BAqA98lphi4rQZAd/#/resolved。它使用了一个非常相似的解决方法,但是稍微更准确地使用RouteData对象而不是RouteParams

@CanActivate((to) => {
    return new Promise((resolve) => {
        to.routeData.data.user = { name: 'John' }

此外,请注意,还有一个用于访问嵌套/父路由“解析”值的示例解决方法,以及您使用1. xUI路由器时期望的其他功能。

请注意,您还需要手动注入完成此操作所需的任何服务,因为Angular Injector层次结构目前在CanActivate装饰器中不可用。简单地导入Injector将创建一个新的注入器实例,而无需从bootstrap()访问提供程序,因此您可能需要存储引导注入器的应用程序范围副本。Brandon在此页面上的第二个Plunk链接是一个很好的起点:https://github.com/angular/angular/issues/4112