昨天跟大家分享了自訂表單元件的作法,但昨天的作法只適用於一個欄位、一個 FormControl
。
雖然 FormControl
裡是可以設 {}
的值,但如果我們真的想要的是一個可以直接用 [formGroup]
、 [formArray]
所使用的元件呢?
沒問題,只要你想要, Angular 都給你
實作開始
大家還記得之前我們做了個「被保人表單」吧?
一開始只有「姓名」、「性別」跟「年齡」這三個欄位,後來我們加了「聯絡資訊」的欄位,這次我們再幫它加個「聯絡地址」的欄位吧!
一般來說,聯絡地址的欄位通常會分成「縣市」、「鄉鎮市區」、「郵遞區號」與「地址」,而「縣市」、「鄉鎮市區」與「郵遞區號」之間會有一些連動邏輯,縣市」與「鄉鎮市區」這兩個欄位也通常會是下拉選單,其他的則是一般的 input
欄位。
首先一樣先把 HTML 準備好,像這樣:
1 | <p><label>聯絡地址:</label></p> |
畫面:
樣式用
inline
的方式設定是方便教學,小朋友們要盡量少用噢!
接著,在 .ts
裡加入地址的相關欄位的 FormGroup
與 FormControl
:
1 | const addressInfoFormGroup = this.formBuilder.group({ |
然後再將其綁與畫面上元素綁定,像這樣:
1 | <ng-container formGroupName="addressInfo"> |
連動邏輯的實作就交給大家練習囉,我們今天沒有要著重於此部分的處理。
至此,我們就完成了第一步的準備工作。
ControlContainer
接下來,我們就要將聯絡地址這塊拆成一個獨立的 Component ─ AddressInfoComponent
。
首先,先將 HTML 搬過去並稍微調整一下:
1 | <ng-container [formGroup]="formGroup"> |
接著在 AddressInfoComponent
裡注入 ControlContainer
:
1 | export class AddressInfoComponent { |
然後加上:
1 | get formGroup(): FormGroup { |
再回到被保人表單裡,把原本的聯絡地址區塊改成:
1 | <p><label>聯絡地址:</label></p> |
至此就大功告成了!是不是超簡單的?!
不過之所以這麼簡單是因為這是 Reactive Forms 的方式,今天的 ControlContainer
不像昨天的 ControlValueAccessor
可以做一次之後,兩種方式都可以使用。
如果今天這個元件是要讓 Template Driven Forms 使用的話,首先要先將 Template 原本用 Reactive Forms 的綁定方式改成使用 Template Driven Forms 的綁定方式,像是這樣:
1 | <ng-container ngModelGroup="addressInfo"> |
然後也不用在 AddressInfoComponent
裡注入 ControlContainer
,而是改在 AddressInfoComponent
的 MetaData 的 viewProviders
裡新增以下設定:
1 | @Component({ |
這樣就能直接用 <app-address-info></app-address-info>
的方式使用這個元件了。
大家覺得,是 Reactive Forms
的方式好用,還是 Template Driven Forms
的方式好用呢?
本日小結
今天的重點主要是讓大家知道要怎麼使用 ControlContainer
這個類別來包裝我們的元件,以達到提昇重用性與維護性的目的。
雖然麻煩的是,它沒辦法像昨天分享的 ControlValueAccessor
一樣,做好了之後可以適用於 Template Driven Forms 與 Reactive Forms ,但好在它的用法其實頗為簡單,主要的差異就只有在 Template Driven Forms 需要靠 viewProvider
,而 Reactive Froms 只要注入就行。
關於 viewProvider 與 provider 的差異,我推薦大家可以去看 Kevin (台灣 Angular GDE)的 [Angular] viewProviders V.S. providers ,我覺得寫得非常的清楚。
此外,如果覺得我分享不好,也可以參考 Kevin 的 [Angular] ControlContainer 的應用
今天的程式碼會放在 Github - Branch: day29 上供大家參考,建議大家在看我的實作之前,先按照需求規格自己做一遍,之後再跟我的對照,看看自己的實作跟我的實作不同的地方在哪裡、有什麼好處與壞處,如此反覆咀嚼消化後,我相信你一定可以進步地非常快!
如果有任何的問題或是回饋,還請麻煩留言給我讓我知道!