路由器插座的Angular 2延迟渲染

Posted

技术标签:

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

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

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

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

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

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

【问题讨论】:

服务哪里都一样?如果是,您可以使用 APP_INITIALIZER 来处理此问题 您可以使用Resolve 类并创建一个Resolver 作为组件的数据提供者,它会在您的组件初始化之前收集数据。 【参考方案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。

以上是关于路由器插座的Angular 2延迟渲染的主要内容,如果未能解决你的问题,请参考以下文章

Angular Universal 不在路由器插座内呈现内容

Angular 2,RC5 路由器插座在另一个路由器插座内

在 Angular 2+ 中,使用路由器插座和嵌套组件有啥区别

在 Angular 2 中使用路由器插座

Angular2 - 具有登录结构的路由器插座

Angular 4 Lazy loading with named router-outlet 不起作用