【问题标题】:Angular 2 delay rendering of router-outlet路由器插座的Angular 2延迟渲染
【发布时间】:2017-04-23 12:59:44
【问题描述】:

我正在开发一个具有多个组件的 Angular 2 应用程序,这些组件依赖于通过 http 服务从服务器加载的一些数据(它是关于用户及其角色的数据)。

如果此数据尚未加载,我的大多数路由组件都会在其 ngOnInit() 方法中抛出错误。数据被加载并存储在注入所有组件的服务中。

有没有办法在我的根组件中延迟渲染当前路由,直到 http 调用完成?

否则我将不得不在所有路由组件的 ngOnInit 中实现某种检查和重试机制,这将非常尴尬。

我已经尝试在调用完成之前隐藏 router-outlet 元素,但这会导致错误提示“无法找到要加载 xxx 的主出口”

【问题讨论】:

  • 服务哪里都一样?如果是,您可以使用 APP_INITIALIZER 来处理此问题
  • 您可以使用Resolve 类并创建一个Resolver 作为组件的数据提供者,它会在您的组件初始化之前收集数据。

标签: javascript angular typescript


【解决方案1】:

创建Router模块时有一个延迟Router初始导航的选项:

RouterModule.forRoot([
    // routes here
], {
    initialNavigation: false // the propery to delay navigation
}),

稍后可以通过 Angular Router 触发初始导航,如下所示:

this.router.initialNavigation();

【讨论】:

  • 连接页面先于日志显示: > Angular 正在开发模式下运行。调用 enableProdMode() 以启用生产模式。 client.js:67 [HMR] 已连接
【解决方案2】:

我使用 CanActivate 守卫完成了这项工作。使其工作的关键是从 canActivate 方法返回一个 Observable。这样,您可以根据需要延迟。

import { CanActivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Rx';
import { StateService } from '../../_services/state.service';
import { Subject } from 'rxjs/Rx';
import { Subscription } from 'rxjs/Subscription';

@Injectable()
export class LoadingGuard implements CanActivate {
    constructor(private state: StateService) {}

    public canActivate(): Observable<boolean> {
        if (!this.state.loading$.getValue()) { 
            return Observable.of(true); 
        }

        let subject = new Subject<boolean>();
        let subscription = this.state.loading$.subscribe(value => {
            if (!value) {
                subject.next(true);
                subject.complete();

                subscription.unsubscribe();
            }
        });

        return subject;
    }
}

上面,StateService 是一个服务,它评估当前用户并为应用程序的其余部分预缓存一些数据。它有一个名为 loading$ 的主题,加载完成后返回 false。

剩下的就是在应用模块中声明守卫。

import { LoadingGuard } from './app/loading-guard/loading-guard';
// other imports omitted

@NgModule({
    // other module properties omitted
    providers: [LoadingGuard]
})
export class AppModule {}

然后在你的路由中声明守卫。

import { LoadingGuard } from './app/loading-guard/loading-guard';
// other imports omitted

export const rootRouterConfig: Routes = [
    { path: 'app', component: AppComponent, 
      canActivate: [LoadingGuard], 
      children: [
        { path: 'index', component: IndexComponent },
        // child routes omitted
      ] },
    { path: 'sign-in', component: SignInComponent },
    { path: '**', redirectTo: 'sign-in' }
];

作为参考,这里是关于 CanActivate 的文档: https://angular.io/docs/ts/latest/api/router/index/CanActivate-interface.html

【讨论】:

  • 不得不拒绝,您使用 stateSevice 没有示例或链接到此类服务。您的答案不完整,浪费了人们的时间。
  • 我能够找到暗指 $loading 的代码,供未来用户使用 levelup.gitconnected.com/…
  • 我可以看出这是多么令人困惑。在此示例中,必须将 StateService 替换为您自己的代码。但是,您会跟踪应用程序何时完成加载。监听加载完成。然后从canActivate()返回true。
猜你喜欢
  • 2018-07-28
  • 1970-01-01
  • 2016-12-30
  • 2017-03-09
  • 1970-01-01
  • 1970-01-01
  • 2017-03-04
  • 2018-11-24
  • 2018-02-27
相关资源
最近更新 更多