2016-09-25 74 views
13

我想异步将组件添加到路由,给定条件Angular 2:如何有条件地异步加载路由中的组件?

下面的例子,它的工作原理(但异步),加载一个组件或其他根据用户角色:

import { UserDashboardComponent } from './user-dashboard.component' 
import { AdminDashboardComponent } from './admin-dashboard.component' 

const role = 'admin' // Just for the example 
const comp = role === 'admin' ? AdminDashboardComponent : UserDashboardComponent 

const routes: Routes = [ 
    { path: '', component: comp }, 
] 

但是,让我们说,我们要检索的API作用,从而异步。有什么办法可以做到这一点?

+1

[点击这里](https://angular.io/docs/ts/latest/guide/router。HTML)并搜索“延迟加载路由配置” – cvsguimaraes

+0

延迟加载没有帮助。看到我的评论@ user32答案。 –

+0

你知道吗? – Dmitry

回答

7

Angular 2支持在模块级别的延迟加载。功能模块异步加载,而不是组件。 您可以制作该组件功能模块。 https://angular.io/docs/ts/latest/guide/ngmodule.html

+2

对不起,我想我没有正确表达自己。我强调“异步”,但我的问题更多的是关于“条件”。延迟加载不是与我的问题“直接”相关的。我的问题是如何加载一个或另一个组件(或一个或另一个模块),取决于应用程序加载时可能异步的条件(假设条件是来自API的用户角色)。我已经更新了我的问题,使得更清楚。任何方式来解决这个问题? –

1

我建议您利用路由器的导航方法以编程方式进行导航。所以你列出了路由器文件中所有可能的路由。然后在你的组件中,根据具体情况调用router.navigate()。

+1

在这种情况下,url将不会相同。 – Manish

+0

正是。我想要的(起初至少)是具有相同的URL,比如说/仪表板,并且取决于它是用户还是管理员来显示UserDashboard或AdminDashboard。也许不是最好的方法,但我想避免这种情况下的不同url,或者更糟糕的是用各种{{* ngIf}}条件来填充组件...... –

4

您可以只定义一个更高级别的组件f.e.包含在路由/仪表板中的DashboardComponent

然后,父组件将根据异步条件将其加载到其模板中。

这样你还需要使用* ngIf,但至少不会混淆子组件模板。

+0

这听起来很有趣并且有意义。我会尽力回到这里!现在我离开线程以欢迎其他答案 –

6

您可以创建一个generic.module.ts这将在声明数组两个组成部分:

import { NgModule }  from '@angular/core'; 
import { BrowserModule } from '@angular/platform-browser'; 
import { UserDashboardComponent } from './user-dashboard.component' 
import { AdminDashboardComponent } from './admin-dashboard.component  

@NgModule({ 
    imports: [ BrowserModule ], 
    declarations: [ UserDashboardComponent,AdminDashboardComponent ] 
}) 
export class GenericModule { } 

这样你将有一个模块,其中包含你想要加载的模块。

现在,下一步将使用编译器异步加载他们:你的组件内部 做以下操作:

import {GenericModule} from './generic.module'; 
import { Component, Input,ViewContainerRef, Compiler, NgModule,ModuleWithComponentFactories,OnInit,ViewChild} from '@angular/core'; 
@Component({ 
    selector: 'generic', 
    template: '<div #target></div>' 
}) 
export class App implements AfterViewInit { 
    @ViewChild('target', {read: ViewContainerRef}) target: ViewContainerRef; 

    constructor(private compiler: Compiler) {} 

    ngAfterViewInit() { 
    this.createComponent('<u>Example template...</u>'); 
    } 

    private createComponent(template: string,role:string) { 
    @Component({template: template}); 
    const mod = this.compiler.compileModuleAndAllComponentsSync(GenericModule); 
    const factory = mod.componentFactories.find((comp) => 
    //you can add your comparison condition here to load the component 
    //for eg. comp.selector===role where role='admin' 
    ); 
    const component = this.target.createComponent(factory); 
    } 
} 

希望这有助于。

+1

这很有意义。虽然,对我来说,对于这种情况我们相当惊讶,人们必须做很多事情,特别是在低层框架范围内。现在我不能让这个被接受的答案,因为我想向这个角色团队开放一个问题。但肯定答案奖励赏金。 –

+0

@AlexJ很高兴听到这可以帮助你。 –

+1

https://github.com/angular/angular/issues/12088有问题,如果感兴趣 –

2

由于您将使用任一部件一条路线,一种解决方案是创建另一个组件,用于这条路线那么它的模板可以参考这两个部件,但与ngIf象下面这样:

<user-dashboard *ngIf="role==='user'"></user-dashboard> 
<admin-dashboard *ngIf="role==='admin'"></admin-dashboard> 
-1

很好的解决办法是“使用验证码”。您可以尝试实现CanActivate/CanLoad接口并将您的条件放入该类。

根据条件,路线被激活。

实施例:

import { Injectable }  from '@angular/core'; 
import { 
    CanActivate, 
    ActivatedRouteSnapshot, 
    RouterStateSnapshot 
}       from '@angular/router'; 
import { Observable } from 'rxjs/Observable'; 
import { Router } from '@angular/router'; 

@Injectable() 
export class AuthorizationGuard implements CanActivate { 
    constructor() {} 

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): 
     Observable<boolean> { 
    let url: string = state.url; 
    return this.canbeLoaded(url); 
    } 

    canbeLoaded(url: string): Observable<boolean> { 
    return Observable.of(true); //put your condition here 
    } 
} 
相关问题