你知道 value 在 FormControl 中是怎麼流動的嗎? 讓我們一步步的追蹤值的流向與變化吧
FormControl / FormGroup 都是繼承自 AbstractControl, 只是各自實作
本篇會先介紹 AbstractControl 中的 updateValueAndValidity, 並帶入大量的範例來幫助吸收
下面這一小段就是今天的主題, 會在程式中做分段說明, 並著重於今天的主題
1 | updateValueAndValidity(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { |
經由上面的註解說明, 讓我們把程式焦點重新集中於以下內容
值的更新 => 事件的觸發 => 上層更新觸發
1 | updateValueAndValidity(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { |
原始碼: 點我
FormGroup 可以乘載 FormControl, 理論上在 FormGroup 中的 setValue/patchValue 是輪巡其下 FormControl 的 setValue/patchValue 並加上一些本身的邏輯
1 | setValue(value: any, options: { |
原始碼: 點我
1 | setValue(value: {[key: string]: any}, options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { |
原始碼: 點我
看起來和我們理解的差不多, 那我們繼續往下
查閱原始碼發現 FormControl.patchValue 就只是多一層, 讓整體感覺都是使用一樣的開發模式
1 | patchValue(value: any, options: { |
原始碼: 點我
什麼都不做就轉呼叫到 FormControl.setValue 了
1 | patchValue(value: {[key: string]: any}, options: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { |
原始碼: 點我
FormGroup.patchValue 基本上和 FormGroup.setValue 一模一樣, 少了一些全域的邏輯而以
順序: patchValue -> setValue -> updateValueAndValidity
範例中有兩個 FormControl, firstName and lastName, 在這個範例中只會單純做 setValue
, 並搭配 emitEvent
、onlySelf
訂閱 valueChanges
監看值的變化
1 | this.firstName = new FormControl(); |
- 設置 firstName => Skye
- 設置 firstName => Kai, emitEvent => false
- 設置 lastName => Wu
- 設置 lastName => Ah, emitEvent => false
1 | console.log( |
這裡可以先自己模擬一下, 會印出那些資訊, 其順序又為何
1 | # 先印出初始值 |
這個範例非常簡單, 就是 emitEvent 有無的差異, 會影響到 updateValueAndValidity 中的 emit 事件
這個範例之後都以 FormGroup + FormControl 來講解
1 | this.firstName = new FormControl(); |
訂閱 FormGroup, 訂閱 FormControl 並印出當下 FormGroup 值的變化
1 | this.formGroup.valueChanges.subscribe((value) => { |
- 設置 firstName => Skye
- 設置 lastName => Wu
1 | this.firstName.setValue("Skye"); |
這裡可以先自己模擬一下, 會印出那些資訊, 其順序又為何
1 | # this.firstName.setValue("Skye"); |
這個範例開始著重於 FormControl value 變化的時間點, 以及 FormGroup value 變化的時間點
延續範例 2, 將 emitEvent、onlySelf 放進來
1 | this.formGroup.valueChanges.subscribe((value) => { |
這裡可以先自己模擬一下, 會印出那些資訊, 其順序又為何
1 | # this.firstName.setValue("Skye", { onlySelf: true }); |
這個範例是最為複雜的一個例子, 建議拿出紙筆稍微紀錄個步驟的變化, 因為有兩個變化題互相交互的問題
1 | this.formGroup.valueChanges.subscribe((value) => { |
這裡可以先自己模擬一下, 會印出那些資訊, 其順序又為何
1 | # 初始值 |
做一個延遲值變的變化題
1 | this.formGroup.valueChanges.subscribe((value) => { |
這裡可以先自己模擬一下, 會印出那些資訊, 其順序又為何
1 | # 初始值 |
範例稍微複雜了一些, 但是如果真的理解 updateValueAndValidity 其中的邏輯順序, 就可以融會貫通 FormGroup / FormControl 變化的時間點.
在較複雜的多欄位交互中可能因為使用了大量的 setValue + valueChanges, 導致出現雷點或鬼打牆的問題, 通常就是這篇提到的邏輯所導致的.
欄位交互的方式很多種, 如果習慣用 Angular form 的開發者, 還是稍微理解一下這些流向會比較好唷.
全範例: 點我
本篇起源是源自 https://blog.kevinyang.net/2020/04/20/angular-form-valuechanges/
其範例較為精簡, 很推薦唷!