今天主要是
https://www.youtube.com/watch?v=282ITUdC12Y&list=PL9LUW6O9WZqgUMHwDsKQf3prtqVvjGZ6S&index=4
這一集是由 Felix Tsai 老師來分享der,感謝大神
首先,先開好片頭導讀的文章,再跟著影片一起看,以後才有能力自己查文件
使用情境:
當Templates不固定時,透過runtime來動態產生Component
重要的API:
ComponentFactoryResolver
用來建component的instance
https://angular.io/api/core/ComponentFactoryResolver
^^^ 錨點,包成一個Directive
https://angular.io/guide/dynamic-component-loader#the-anchor-directive
可用放Component的Container
可將多個Views附加到Component的Container
https://angular.io/api/core/ViewContainerRef
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[dynamic-host]',
})
export class DynamicDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
@NgModule({
declarations: [DynamicDirective], // Directive放在declarations
entryComponents: [ComponentAComponent,ComponentBComponent] // 動態載入的元件加在這裡,避免被ng build移除
})
<ng-template dynamic-host></ng-template>
^^^ 加入anchor(錨點)
建立2個要動態產生的component
app.component.ts 動態產生元件
import { Component, ComponentFactoryResolver, ViewChild, AfterViewInit } from '@angular/core';
import { DynamicDirective } from './dynamic.directive';
// 要動態產生的Component
import { ComponentAComponent } from ...;
import { ComponentBComponent } from ...;
@Component({...})
export class AppComponent implements AfterViewInit {
// 在app.component.html注入的ViewContainerRef
// anchor(錨點)
@ViewChild(DynamicDirective) dynamicHost;
constructor(private resolver: ComponentFactoryResolver){}
ngAfterViewInit(){
// 專門生產ComponentAComponent instance的factory
const factory = this.resolver.resolverComponentFactory(ComponentAComponent);
// 在app.component.html注入的ViewContainerRef
// <ng-template dynamic-host></ng-template>
const ref = this.dynamicHost.viewContainerRef;
// https://angular.io/api/core/ViewContainerRef#createcomponent
// 實例化一個component,並host view插入viewContainerRef
ref.createComponent(factory);
}
}
<input type="radio" name="showComponent" (change)="onRadioChange('A')" >
<label for="showComponent">select component A</label>
<input type="radio" name="showComponent" (change)="onRadioChange('B')" >
<label for="showComponent">select component B</label>
<ng-template dynamic-host></ng-template>
^^^ 加入anchor(錨點)
onRadioChange(value){
const factory = this.resolver.resolverComponentFactory(componentMapping[value]);
^^^^^^^^^^^^^^^^^^^^^
const ref = this.dynamicHost.viewContainerRef;
ref.clear(); // 沒clear()的話,舊的component會一直存在
ref.createComponent(factory);
}
export const componentMapping = {
A: ComponentAComponent,
B: ComponentBComponent,
}
@ViewChildren(DynamicDirective) dynamicHost; // 多個anchor(錨點)
^^^^^^^^^^^^^ 複數型
onRadioChange(value){
const factory = this.resolver.resolverComponentFactory(componentMapping[value]);
// 對每個anchor(錨點)操作
const ref = this.dynamicHost._results.forEach(item => {
^^^
const ref = item.viewContainerRef;
ref.clear(); // 沒clear()的話,舊的component會一直存在
ref.createComponent(factory);
});
}
A 報表 -- A報表的Filter (其Input,DateTimePicker,Select)
B 報表 -- B報表的Filter (其Input,DateTimePicker,Select)
此處 Felix 大大分享珍貴的應用,圖難以畫出,請大家看影片19分的地方
把FilterBase<T>
打出來,以後自己參考用
FilterBase<T>
value: T, // 泛型
key:string,
type:string // 例如:Input、DataTimePicker、Select
sort:number, // 欄位的順序
validation: any // reactive form的validation
@Input() data = ''; // 假設要動態產生的元件有一個參數 data
// 其他應用
@Input() form: FormGroup; // 丟form進去動態元件
@ViewChild(DynamicDirective) dynamicHost;
constructor(private resolver: ComponentFactoryResolver){}
ngAfterViewInit(){
const factory = this.resolver.resolverComponentFactory(ComponentAComponent);
const ref = this.dynamicHost.viewContainerRef;
const instance = ref.createComponent(factory).instance;
create完取得實體 ^^^^
instance.data = 'abc';
}