利用 Angular 動態元件,製作高彈性客製化頁面! (下)
前言
接續上一篇利用Angular動態元件,製作高彈性客製化頁面! (上)
我們完成了 在頁面上自由動態產生 component 的功能
這一篇則會接下去帶大家完成
- 刪除已經產生出的元件
- 在創立 component 時,傳入 Input 資料
讓我們的功能更完整,更貼近實戰使用!
核心知識會用到: ComponentRef
成果如下
https://huskylin.github.io/dynamic-component-demo-2/
刪除已經產生出的元件
概念
要刪除動態產生的元件,首先我們得知道頁面上的眾多元件中
我們如何找出要刪除的那一個?
概念是這樣
- 動態創立元件時,給予一個唯一值,記錄在該元件內
- 我們對元件按下刪除件的時候,利用 Output ,發送出該元件的唯一值
- 獲得唯一值後,在對應的 ComponentRef 中,利用 destroy 方法移除元件
程式碼
第一步,動態創立元件時,給予一個唯一值,記錄在該元件內
custom.component.ts
createComponent(component) {
...
// 記錄 component 唯一值
wrapperRef.instance['uniqueKey'] = ++this.childUniqueKey;
// 儲存 wrapper 跟 target 的 ref,之後更新資料、刪除元件時會用
this.customService.pushWrapperRefs(wrapperRef);
this.customService.pushChartRefs(targetRef);
// 如果開著刪除模式,新增的元件也要開啟刪除模式
this.customService.refreshRemoveMode(this.removeable);
// 訂閱刪除事件
const self = this;
wrapperRef.instance['remove'].subscribe(componentIdx => {
self.customService.removeComponent(componentIdx);
});
}
解說:
這邊的 wrapperRef.instance[‘uniqueKey’]
會在該元件內創建一個名為uniqueKey的屬性 並且儲存傳進去的值
就跟平時在寫 component 時
寫export class MyComponent { ... uniqueKey = 123 }
是一樣的意思
customService.pushWrapperRefs、customService.pushChartRefs
則是將 ComponentRef 儲存到 service 的陣列中,方便日後做刪除的操作訂閱刪除事件
別忘了訂閱元件的 EventEmitter ,這樣按下元件刪除鍵時才會收到動作
第二步,我們對元件按下刪除件的時候,利用 Output ,發送出該元件的唯一值
small.component.ts
@Input() uniqueKey: number;
@Output() remove: EventEmitter<number> = new EventEmitter();
removeComponent() {
this.remove.emit(this.uniqueKey);
}
第三步,獲得唯一值後,在對應的 ComponentRef 中,利用 destroy 方法移除元件
custom.service.ts
removeComponent(uniqueKey) {
const idx = this.wrapperRefs.findIndex(e => e.instance.uniqueKey === uniqueKey)
this.wrapperRefs[idx].destroy();
this.wrapperRefs = this.wrapperRefs.filter(e => e.instance.uniqueKey !== uniqueKey);
}
Angular 的 ComponentRef 提供了一個 destroy 的方法
Destroys the component instance and all of the data structures associated with it.
wrapperRefs 是一個儲存了我們所創立的元件的陣列
根據唯一值找出我們需要刪除的元件,並且呼叫 destroy 方法
就完成刪除的功能了~
在創立 component 時,傳入 Input 資料
我們的元件,通常也會需要傳入參數
畢竟元件通常是把功能抽出來
再把不同資料傳入後呈現不同的畫面
那動態產生元件時要怎麼傳入資料呢
答案也是使用 ComponentRef.instance
程式碼如下:
updateInputData(component, targetRef) {
// 產生 InputData
const inputData = this.utilsService.getData(component.name, year);
// 傳入到 Input 中,會觸發在 ngOnInit
targetRef.instance['data'] = inputData;
// 產生 change
const changes = {
data: new SimpleChange(undefined, inputData, false)
};
// 傳入到 Onchange
if (typeof targetRef.instance.ngOnChanges !== 'undefined') {
targetRef.instance.ngOnChanges(changes);
}
}
解說:
- targetRef.instance[‘data’] = inputData;
會傳值到元件的@Input() data
中
注意這邊會觸發的生命週期是 OnInit 階段 - 如果想要觸發 OnChanges,就可以看後半段的程式碼
先產生一個 change ,再透過 targetRef.instance.ngOnChanges(changes) 來觸發
這樣就完成資料的傳值功能了~
成果展示
刪除元件
開啟刪除模式後
這邊用了個類似手機APP移除的視覺效果
(UX方面,滑鼠移上去的時候再停止動畫,避免抖到點不到XD)
並且透過不同的 class name 達成不同的抖動延時
點擊按鈕後就會觸發 EventEmitter ,並且透過 ComponentRef.destroy() 刪除
透過動態元件呈現交叉分析
這次我們在每個圖塊多加上了自己的時間篩選
以呈現動態元件的優點:
使用者可以高度客製化希望看到的頁面
另外在創立元件的選單上方,也加入了年份選擇
以呈現同樣的元件可以透過不同的 Input 資料
畫出不同的圖表內容
這次展示的內容都只是提供大家一個概念
實際上可以應用的場景當然不限於圖表、數據呈現
DEMO 連結在這邊,歡迎上去玩玩看
https://huskylin.github.io/dynamic-component-demo-2/
完整程式碼在 Github 專案上
真心覺得 Angular 的這個功能超酷
終於打完這篇的分享啦,灑花~