angular dynamic component 筆記

使用到動態組件是由於我在作一個Table的控件,表格中有按鈕等控件,並具備相應邏輯,同時項目中多處使用到該表格,故想提取一個可複用的控件以減小工做量。主要參考的文章是大神的修仙之路Angular 4.x 動態建立組件以及官方文檔Dynamic Component Loaderhtml

這裏主要簡要記錄一下我本身的理解。segmentfault

動態組件的建立

  • 在/src/app目錄下經過如下命令能夠建立一個簡單的TestComponent
ng generate component test
  • 對應須要引用該動態組件的父組件(eg: ParentComponent),首先咱們要將TestComponent引入其對應的ParentModule
import { TestComponent } from '.../test.component'
import { CommonModule } from '@angular/common';

@NgModule({
  imports: [
    ...
  ],
  declarations: [ ..., TestComponent ],
  entryComponents: [TestComponent]
})

*注意最後咱們用了一個entryComponent的命令,這是由於通常而言,angular編譯器會根據代碼自動生成全部組件的ComponentFactory,但對於動態插入的組件,其在父組件的代碼中沒有對於的模板選擇器(eg:<test></test>),故爲了能讓編譯器能生成動態組件的ComponentFactory,須要人手告訴angular去生成。瀏覽器

Generally, the Angular compiler generates a ComponentFactory for any component referenced in a template. However, there are no selector references in the templates for dynamically loaded components since they load at runtime.

To ensure that the compiler still generates a factory, add dynamically loaded components to the NgModule's entryComponents array:app

*ComponentFactory代碼定義以下,個人理解它是angular編譯得出的js方法,交給瀏覽器運行,從而用來實際建立組件;ide

class ComponentFactory<C> {
  get selector: string
  get componentType: Type<any>
  get ngContentSelectors: string[]
  get inputs: {...}
  get outputs: {...}
  create(injector: Injector, projectableNodes?: any[][], rootSelectorOrNode?: string | any, ngModule?: NgModuleRef<any>): ComponentRef<C>
}

*entryComponent則告訴angular編譯器,在用戶交互過程當中,須要動態生成某個組件,故命令angular生成該組件的ComponentFactory,以供後續組件的動態建立使用。
*導入CommonModule,是爲了其後使用ngIf,ngFor,<ng-template>等指令。ui

  • 在ParentComponent中動態添加組件,代碼以下:
...
import { ViewContainerRef, AfterViewInit, ViewChild, ComponentFactoryResolver} from '@angular/core';
import { TestComponent } from '.../test.component'
...
export class ParentComponent{
  @ViewChild("Container", { read: ViewContainerRef }) vcRef: ViewContainerRef;
  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
  ...
  ngAfterViewInit() {
     let componentFactory = this.componentFactoryResolver.resolveComponentFactory(TestComponent);
     this.vcRef.clear();
     let dynamicComponent =  vcRef.createComponent(componentFactory);
     ...
  }
}
  • 在test.component.html中添加代碼以下:
<ng-template #Container></ng-template>

*ViewContainerRef 類型表明裝載視圖的容器類this

Represents a container where one or more Views can be attached

*ViewChild用於獲取對應ViewContainerRef中的第一個元素或對應的ViewContainerRef實例code

You can use ViewChild to get the first element or the directive matching the selector from the view DOM. If the view DOM changes, and a new child matches the selector, the property will be updated.

*此處利用定義html錨點#container,當實例化ViewChild時,傳入第一個參數爲錨點名字「container」,第二個參數{read: <Type>}爲查詢條件,設置查詢的類型,此處設置返回ViewContainerRef的實例;component

*componentFactoryResolver提供生成componentFactory的方法;htm

*因爲ViewChild所進行的視圖查詢是在ngAfterViewInit前調用的,因此對vcRef的操做要在ngAfterViewInit後進行,不然vcRef是undefined,最後利用vcRef的createComponent方法,根據生成的componentFactory,可動態組件;

*對組件dynamicComponent的操做,可經過如下代碼進行,例如,動態組件TestComponent中有@Input() Data,可經過.data進行賦值;

(<any>dynamicComponent.instance).data = "test";

至此,爲我對動態組件的理解。利用動態組件的Table控件實現會整理進下一篇文章。

相關文章
相關標籤/搜索