2016-09-25 2 views
13

Я хотел бы асинхронно подключить компонент к маршруту, с условием.Угловой 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

Lazy loading не помогает здесь. См. Мой комментарий к @ user32 answer. –

+0

Вы поняли это? – Dmitry

ответ

7

Угловой 2 поддерживает ленивую загрузку на уровне модуля. Функциональные модули загружаются асинхронно, а не компонент. Вы можете создать этот компонентный модуль. https://angular.io/docs/ts/latest/guide/ngmodule.html

+2

Извините, я думаю, что не правильно сказал. Я подчеркнул «асинхронный», но моя проблема связана скорее с «условием». Ленивая загрузка не «напрямую» связана с моей проблемой. Моя проблема заключается в том, как загружать один компонент или другой (или один модуль или другой) в зависимости от состояния, которое может быть асинхронным (например, условие является роль пользователя, которое приходит из API) при загрузке приложения. Я обновил свой вопрос, сделав это более ясным. Любой способ решить это? –

1

Советуем использовать программную навигацию, используя навигационный метод маршрутизатора. Таким образом, вы перечисляете все возможные маршруты в файле маршрутизатора. Затем в своем компоненте вы вызываете router.navigate() на основе конкретного случая.

+1

В этом случае URL не будет таким же. – Manish

+0

Точно. То, что я хочу (по крайней мере, по крайней мере), это иметь один и тот же url, скажем,/dashboard, и в зависимости от того, является ли это Пользователь или Администратор, чтобы показывать 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

Очень хорошее решение может «Использовать 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 
    } 
} 
Смежные вопросы