2016-12-30 30 views
1

我目前正在獲取一個數組(在resourceTypes下面的代碼中)和一個ngSwitch。正如你所看到的,取決於TypeName,我創建了一種不同類型的組件/指令(config-resource-editor或mvc-resource-editor或...)。但是我不喜歡這個代碼,因爲當我創建更多的資源編輯器時,我總是需要修改這些代碼等等。我如何重構代碼,以便根據類型創建正確的資源編輯器,而不需要使用ng-switch。 我看着ng-content,我想我必須做些什麼,但我看不到它。如何避免ng開關和生成組件類型

TL; DR:我如何重構下面的代碼,所以我不必再使用ngSwitch,而是將類型「耦合」到組件。

<div *ngFor="let aType of resourceTypes; let i = index" role="tabpanel" class="tab-pane" [ngClass]="{'active': i==0}" [attr.id]="aType.Name"> 
       <span *ngSwitch="aType.Name"> 
        {{aType.Name}} tab content here 
        <config-resource-editor [application]="application" ngSwitchWhen="Config" template></config-resource-editor> 
        <mvc-resource-editor [application]="application" ngSwitchWhen="MVC" template></mvc-resource-editor> 
        <other-resource-editor [application]="application" ngSwitchWhen="Other" template></other-resource-editor> 
        <wcf-resource-editor [application]="application" ngSwitchWhen="WCF" template></wcf-resource-editor> 
        <web-resource-editor [application]="application" ngSwitchWhen="Web" template></web-resource-editor> 
        <webapi-resource-editor [application]="application" ngSwitchWhen="WebAPI" template></webapi-resource-editor> 
       </span> 
      </div> 

如果有什麼不明確的地方,請隨時詢問。

在此先感謝

+0

另一種方法是http://stackoverflow.com/questions/36325212/angular-2-dynamic-tabs-with-user-click-chosen-components/36325468#36325468 –

+0

的NgComponentOutlet看上去不錯,但它不是」還沒有。這將是一個可能的解決方案,但看起來也有點冒失。感謝您的網址! – Maximc

+0

爲什麼它看起來很亂?這與'NgComponentOutlet'好像很相似。主要區別在於,在鏈接中添加的元素被添加到包裝中,而'NgComponentOutlet'只是將動態添加的元素添加爲兄弟,從而消除了對一些代碼行的需要。除了偏好之外,我沒有看到其中一個或另一個的強烈理由。我只是試圖表現這種方式,因爲我認爲它會被大多數人所喜歡。路由器也使用這種添加組件的方式。唯一的缺點是不同的綁定不能用於不同的類型(至少不容易)。 –

回答

2

您可以創建一個包裝組件,並使用@ViewChild擺脫開關盒。

您的包裝看起來會是如下:

@Component({ 
    selector: 'my-wrapper', 
    template: `<div #target></div>` 
}) 
export class MyWrapper { 
    @ViewChild('target', {read: ViewContainerRef}) target; 
    cmpRef: ComponentRef<Component>; 
    currentComponent: Component; 
    private isViewInitialized: boolean = false; 
    constructor(
      private componentFactoryResolver: ComponentFactoryResolver, 
      private cdRef: ChangeDetectorRef, 
      private wrapperService: WrapperService 
    ){} 

    updateComponent() { 
     if (!this.currentComponent) { 
      return; 
     } 
     if (!this.isViewInitialized) { 
      return; 
     } 
     if (this.cmpRef) { 
      this.cmpRef.destroy(); 
     } 
     let factory = this.componentFactoryResolver.resolveComponentFactory(this.currentComponent); 
     this.cmpRef = this.target.createComponent(factory); 
    } 

    ngAfterViewInit() { 
     this.cdRef.detectChanges(); 
     this.isViewInitialized = true; 
     this.currentComponentSubscription = this.wrapperService.getCurrentComponent().subscribe(c => { 
      this.currentComponent = c; 
      if (c) { 
       this.updateComponent(); 
      } 
     }); 
    } 

    ngOnDestroy() { 
     if (this.cmpRef) { 
      this.cmpRef.destroy(); 
     } 
     if(this.currentComponentSubscription){ 
      this.currentComponentSubscription.unsubscribe() 
     } 
    } 
} 

創建WrapperService和寫入當前組件一個getter/setter和注意吸氣應返回BehaviorSubject:

private _currentComponent: BehaviorSubject<Component> = new BehaviorSubject(null); 
getCurrentComponent(): BehaviorSubject<Component> { 
    return this._currentComponent; 
} 

setCurrentComponent(value: Component) { 
    this._currentComponent.next(value); 
} 

使用用於替代ngSwitch的MyWrapper組件選擇器,並使用定義resourceTypes的父組件中的包裝器服務設置當前組件。

您還需要添加附着/獨棟到entryComponents在@NgModules組件:

@NgModule({ 
    entryComponents: <array of components> 
}) 

注意:當設置_currentComponent您需要提供參考組件,而不是一個字符串。

Credits:@Gunter我也提到他的例子,以得到這個去爲我。

+0

謝謝,但它是給的問題,我跟着博客帖子,它沒有問題的工作。 (對不起,不發佈問題) – Maximc