您好,登錄后才能下訂單哦!
源碼:https://github.com/Karin001/ngx-dynamic-form
動態表單使用場景
有時候我們需要一個靈活的表單,這個表單可以根據用戶的選擇,或者服務器返回的信息進行重新配置,比如:增加或刪除一組input元素、一組select元素,等等。
在這樣的情況下,如果一開始就在模板里寫下所有的表單,利用一個ngif樹狀結構進行選擇控制,程序會變得比較冗余。
這時。程序最好是能夠根據用戶的選擇(driven by configuration)或者服務器的響應,自動生成所需要的表單。這就是動態表單要處理的業務。
組件生成的相關概念組件的兩個構成
要動態生成表單,需要先理解組件是如何生成的。
一個angular組件由兩部分所組成。
Wrapper
Wrapper能夠與組件進行交互,當一個Wrapper初始化完成后,就已經幫我們實例化了一個組件。同時,它也負責組件的change detection,以及觸發鉤子函數比如ngOnInit,ngOnChanges。
View
View負責呈現渲染過后的模板,將組件的外貌展示出來,并且能夠觸發Wrapper的change detection。一個組件可以有多個view,每一個view可以通過調用angular提供的兩個函數自行生成和銷毀,這個過程不用頂層的視圖參與。
組件的通常加載方式(非動態加載方式)
通常情況下,我們都是把組件內嵌到根組件或者另一個組件當中使用。嵌入的組件稱為子組件,被嵌入的稱為父組件。這時,當我們的子組件代碼在被編譯時,會生成一個組件工廠component factory(這是angular核心類ComponentFactory的一個實例),和一個hsot view,host view負責本組件在父組件視圖內生成該組件的dom節點,以及生成該組件的wrapper和view。
動態加載組件
而當我們想要將一個動態組件插入某個組件視圖時,則無法取得這個動態組件的實例,因為這些是非動態組件編譯器做的事。
實現動態組件
angular提供了一些函數解決上面的難題,要使用這些函數我們需要注入兩個對象。
constructor( private componentFactoryResolver: ComponentFactoryResolver, private viewcontainerRef: ViewContainerRef, ) { }
我們注入了ComponentFactoryResolver,和ViewContainerRef。
ComponentFactoryResolver上提供了一個方法(resolveComponentFactory()),該方法接收一個組件類作為參數,生成一個基于該組件類的組件工廠,也就是我們之前提到的那個組件工廠。
ViewContainerRef提供了一個方法(createComponent()),該方法接收組件工廠作為參數,在該視圖中生成子組件。(我個人的理解是它處理了host view所做的事,為組件生成了wrapper和view)
實現動態表單
上文簡要的介紹了實現動態組件的一些技術,現在開始思考如何做一個動態表單。
具體思路
我們想要做出一個獨立的動態表單模塊,當我們想要使用動態表單時,只需簡單引入這個模塊,稍加配置即可使用。
我們希望這個模塊做好了后,在頂層使用者的角度會是這樣一個工作流程:
我們可以很容易的做出一個具有輸入屬性的組件,問題的核心在于這個組件是如何根據輸入屬性生成我們想要的表單。
也就是說,是它自己調用ComponentFactoryResolver和ViewContainerRef進行組件的動態生成,還是交給別人處理。
下圖是實現思路:
實際上我們把動態表單拆分成了一個個小的動態組件(不預先加載),由外層的一個組件充當一個容器,所有的動態組件都會在里面進行生成和銷毀,他們共同組成了一個動態表單。調用ComponentFactoryResolver和ViewContainerRef生成組件的的這部分邏輯沒有集成在外層容器中,而是交給了一個自定義的指令和ng-container。因為指令沒有視圖,他通過注入ViewContainerRef獲取到的是宿主的視圖容器。由于ng-container不會被渲染,所以獲取到的視圖容器就是外層組件容器的視圖容器。
這么處理的好處就是不需要由外層組件統一對各個拆分的動態組件進行管理,相當于是由動態組件自己進行管理。
外層組件容器大概會是下面這樣:
<form> <ng-container *ngFor="let config of configs" [自定義指令] > </ng-container> </form>
configs是用戶的配置數據,自定義指令寄宿在ng-container中,根據config渲染出各自的動態組件,而ng-container是透明的。
看一下代碼目錄結構,最后會是這個樣子
以上就是大體的實現思路了,具體還有許多細節可以關注文章開頭提到的那兩篇文章,講的很詳細。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。