Angular 2: How to conditionally load a Component in a Route asynchronously?

…衆ロ難τιáo~ 提交于 2019-12-03 03:47:33

问题


I'd like to attach a component to a route asynchronously, given a condition.

The following example, which works (but is asynchronous), loads one component or another depending on the user role:

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 },
]

But, let's say we want to retrieve the role from an API, thus asynchronous. What's the way to accomplish that?


回答1:


You could create a generic.module.ts which will have both components in declarations array:

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 { }

this way you will have a module that contains the modules which you want to load.

Now next step will be to load them asynchronously using compiler: inside your component do following:

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);
  }
}

Hope this helps.




回答2:


Angular 2 supports lazy loading at module level. Feature modules are loaded asynchronously, not component. You can make that component feature module. https://angular.io/docs/ts/latest/guide/ngmodule.html




回答3:


You could just define a higher-level component f.e. DashboardComponent which is included at route /dashboards

The parent component is then supposed to load the children in its template based on the asynchronous condition.

This way you will also need to use the *ngIf but at least its not cluttering the child components templates.




回答4:


Since you will be using one route for either component, one solution is create another component for that route then its template could refer to both components but with an ngIf like below:

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



回答5:


I advice you make use of navigating programatically using the router's navigate method . So you list all the posible routes in the router file .Then in your component you call router.navigate() based on the specific case .




回答6:


Very good solution could be "Use auth-guard". You can try implementing interfaces CanActivate/CanLoad and put your condition in that class.

Based on condition, routes gets activated.

Example:

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
  }
}


来源:https://stackoverflow.com/questions/39688929/angular-2-how-to-conditionally-load-a-component-in-a-route-asynchronously

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!