模版組件有的時後會需要能夠動態被載入,在這邊會講要如何利用ComponentFactoryResolver來動態加入組件
本篇的例子是需要動態載入廣告橫幅,因為廣告內容會由幾個不同的團隊來打造,要在同一個區塊循環播放不同的廣告,因此較難把不同的廣告放在同一個component,這時後就會需要用到動態載入的功能
完整範例請見: live example / download example
在架構介紹的地方有介紹到,directive是一個沒有view的component,可以使用在html裡。
在這邊因為需要動態載入元件,會需要先建立一個directive,讓angular知道要把要動態載入的元件放在那邊。
ad.directive.ts
這個檔案的內容如下:
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[ad-host]',//這個directive的名字
})
export class AdDirective {
constructor(public viewContainerRef: ViewContainerRef) { }//在directive裡去取得View元件以方便做操作
}
首先我們將這個directive命名為[ad-host]
,然後注入ViewContainerRef
,ViewContainerRef可以讓我們得知目前所在的HTML元素中包含的View內容,也可以透過它來改變View的結果(ex: 動態的產生Component、移除某個Component等等)。
使用上面的directive的html碼如下
<div class="ad-banner">
<h3>Advertisements</h3>
<ng-template ad-host></ng-template>
</div>
這邊可以看到我們使用ng-template來應用剛剛所創建的directive
,ng-template指令表示一個Angular模板,這個標籤的內容將包含template的一部分,然後可以與其他template一起組成來成為最終的組件模板。使用ng-template標籤只是定義一個template,但是我們還沒有使用它。
下面是src/app/ad-banner.component.ts
的內容
export class AdBannerComponent implements AfterViewInit, OnDestroy {
@Input() ads: AdItem[];//要輪播顯示的廣告
currentAddIndex: number = -1;
@ViewChild(AdDirective) adHost: AdDirective;//宣告剛剛建立的Directive,並藉由<ng-template ad-host>取得傳入的adHost
subscription: any;
interval: any;
constructor(private componentFactoryResolver: ComponentFactoryResolver) { }
ngAfterViewInit() {
this.loadComponent();
this.getAds();
}
ngOnDestroy() {
clearInterval(this.interval);
}
//最重要動態載入廣告的程式碼都在這個function裡
loadComponent() {
//決定要顯示那則廣告
this.currentAddIndex = (this.currentAddIndex + 1) % this.ads.length;
let adItem = this.ads[this.currentAddIndex];
//透過ComponentFactoryResolver來解析component組件
let componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);
//透過剛剛從AdDirective傳來的資訊取得要載入ad的template
let viewContainerRef = this.adHost.viewContainerRef;
//將template內容清掉
viewContainerRef.clear();
//動態建立template並顯示在畫面上
let componentRef = viewContainerRef.createComponent(componentFactory);
(<AdComponent>componentRef.instance).data = adItem.data;
}
//通過這個方法,每三秒會動態載入不同的廣告元件
getAds() {
this.interval = setInterval(() => {
this.loadComponent();
}, 3000);
}
}
loadComponent是動態載入元件最關鍵的程式碼片段,程式碼裡都有下註解。
最終出來的成果如下圖