模版組件有的時後會需要能夠動態被載入,在這邊會講要如何利用ComponentFactoryResolver來動態加入組件
本篇的例子是需要動態載入廣告橫幅,因為廣告內容會由幾個不同的團隊來打造,要在同一個區塊循環播放不同的廣告,因此較難把不同的廣告放在同一個component,這時後就會需要用到動態載入的功能
完整範例請見: live example / download example
The anchor directive
在架構介紹的地方有介紹到,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等等)。
Loading components
使用上面的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,但是我們還沒有使用它。
Resolving components
下面是src/app/ad-banner.component.ts的內容
export class AdBannerComponent implements AfterViewInit, OnDestroy { @Input() ads: AdItem[];//要輪播顯示的廣告 currentAddIndex: number = -1; @ViewChild(AdDirective) adHost: AdDirective;//宣告剛剛建立的Directive,並藉由取得傳入的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); ( componentRef.instance).data = adItem.data; } //通過這個方法,每三秒會動態載入不同的廣告元件 getAds() { this.interval = setInterval(() => { this.loadComponent(); }, 3000); } }
loadComponent是動態載入元件最關鍵的程式碼片段,程式碼裡都有下註解。
最終出來的成果如下圖