【问题标题】:Angular 2: How to conditionally load a Component in a Route asynchronously?Angular 2:如何有条件地异步加载路由中的组件?
【发布时间】:2017-02-02 23:25:46
【问题描述】:

给定条件,我想将组件异步附加到路由。

以下示例可以正常工作(但是异步的),它根据用户角色加载一个或另一个组件:

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 中检索角色,因此是异步的。有什么方法可以做到这一点?

【问题讨论】:

  • Click here 并搜索“延迟加载路由配置”
  • 延迟加载在这里没有帮助。请参阅我对@user32 答案的评论。
  • 你弄明白了吗?

标签: angular typescript angular2-router


【解决方案1】:

非常好的解决方案可能是“使用 auth-guard”。您可以尝试实现接口 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
  }
}

【讨论】:

  • 如果在某种意义上使用,这个答案中描述的方法可以工作。我不明白反对票。
【解决方案2】:

由于您将为任一组件使用一个路由,因此一种解决方案是为该路由创建另一个组件,然后其模板可以引用这两个组件,但使用 ngIf 如下所示:

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

【讨论】:

    【解决方案3】:

    您可以创建一个 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);
      }
    }
    

    希望这会有所帮助。

    【讨论】:

    • 这很有意义。虽然,对于这种情况,一个人必须做这么多事情,特别是在低级框架范围内,这让我感到非常惊讶。现在我不能把它作为公认的答案,因为我想为此向 Angular 团队提出一个问题。但肯定答案会奖励赏金。
    • @AlexJ 很高兴听到这对您有帮助。
    • 我不认为这是一个值得尝试的解决方案,因为您需要将编译器发送到浏览器才能使其正常工作,甚至是 hacky。
    【解决方案4】:

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

    然后父组件应该根据异步条件在其模板中加载子组件。

    这样您还需要使用 *ngIf,但至少不会弄乱子组件模板。

    【讨论】:

    • 这听起来很有趣也很有道理。我会尝试回到这里!现在我将线程保持打开状态以欢迎其他答案
    【解决方案5】:

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

    【讨论】:

    • 在这种情况下 url 将不一样。
    • 没错。我想要的(至少一开始)是拥有相同的 url,比如说 /dashboard,并且取决于它是用户还是管理员来显示 UserDashboard 或 AdminDashboard。也许不是最好的方法,但我想避免在这种情况下使用不同的 url,或者更糟糕的是用各种 {{*ngIf}} 条件填充组件......
    【解决方案6】:

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

    【讨论】:

    • 对不起,我想我表达的不对。我强调“异步”,但我的问题更多是关于“条件”。延迟加载与我的问题没有“直接”关系。我的问题是如何根据应用程序加载时可能是异步的条件(假设条件是来自 API 的用户角色)加载一个或另一个组件(或一个模块或另一个)。我已经更新了我的问题,使其更加清楚。有什么办法解决吗?
    猜你喜欢
    • 2017-11-20
    • 1970-01-01
    • 2018-03-20
    • 1970-01-01
    • 2019-01-04
    • 2023-04-04
    • 1970-01-01
    • 2016-07-25
    • 2016-10-04
    相关资源
    最近更新 更多