---
# System prepended metadata

title: 動態生成Angular Component

---

# 動態生成Angular Component
### 動機
在預約視圖裡，用戶希望在週視圖的header的日期旁邊要有假期資訊，但fullcalendar不支援調整週視圖header，所以花了點時間研究。

> 有時候第三方套件本身沒有提供相關的API去調整UI的時候，此時便可以透過此方法自行插入component到指定的DOM上。

### 舊的做法
在我寫這篇文章之前，我所知道的動態生成組件會需要兩個東西
* ~~[ComponentFactoryResolver (已棄用)](https://angular.io/api/core/ComponentFactoryResolver)~~
* [ViewContainerRef](https://angular.io/api/core/ViewContainerRef)
> 具體使用範例方式可參考[此處](https://stackblitz.com/edit/angular-componentfactoryresolver-example?file=src%2Fapp%2Fapp.component.ts)

動態組件插入的位置看的是ViewContainerRef，如果今天插入的位置是第三方套件，我只拿的到它的DOM，那這時該怎麼辦呢

### 解決方法
`@angular/core`有提供一個方法`createComponent()`，它能讓我們自行決定組件要插入的位置(透過DOM)

---

給fullcalendar的DOM掛上我們自己寫的Component

``` typescript
/**
 * @param host 要掛到哪個目標DOM上
 * @param tooltip 就是個tooltip
 */
dynamicAddTooltip(host: Element, tooltip: string) {
    // 這邊可以為任意的Element(不一定要是Text)
    const textNode = document.createTextNode(tooltip);
    // 創建Component
	const autoTooltipRef = createComponent(AutoTooltipComponent, {
        environmentInjector: this.applicationRef.injector,
        // 這邊對應的是組件內的<ng-content>
        projectableNodes: [[textNode]]
    });
    // 調整組件內的@Input的值
	autoTooltipRef.instance.maxLine = 1;
    // 讓這個動態生成的組件也能進到angular更新檢查機制裡
	this.applicationRef.attachView(autoTooltipRef.hostView);
    // 把組件掛到第三方套件內指定的DOM上
	host.appendChild(autoTooltipRef.location.nativeElement);
}
```
> 補充說明：
> applicationRef的來源是透過constructor注入進來的
> ``` typescript
> import { ApplicationRef } from '@angular/core';
> 
> constructor(private applicationRef: ApplicationRef) {}
> ```


### 結果圖

![](https://hackmd.io/_uploads/rkz4chpAh.png)

