本篇文章跟大家介紹一下Angular使用ControlValueAccessor實作自訂表單控制項的方法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。
我們在實際開發中,通常會遇到各種各樣的客製化功能,會遇到有些元件會與Angular 的表單進行交互,這時候我們一般會從外部傳入一個FormGroup 對象,然後在元件的內部寫相應的邏輯對Angular 表單進行操作。如果我們只是對表單中的一個項目進行定制,將整個表單物件傳入顯然不合適,並且組件也會顯得臃腫。
<form [formGroup]="simpleForm"> <br/> <other-component [form]="simpleForm"></other-component> <br/></form><br/>
那麼,我們能不能像原生表單一樣去使用這些自訂元件呢?目前,開源元件 ng-zorro-antd 表單元件能和原生表單一樣使用 formControlName 這個屬性,這類元件就叫自訂表單元件。 【相關推薦:《angular教學》】
在Angular 中,使用ControlValueAccessor 可以實現元件與外層包裹的form 關聯起來。
ControlValueAccessor是用於處理以下內容的介面:
ControlValueAccessor
ControlValueAccessor 介面定義了四種方法:
writeValue(obj: any): void<br/><br/>registerOnChange(fn: any): void<br/><br/>registerOnTouched(fn: any): void<br/><br/>setDisabledState(isDisabled: boolean)?: void<br/>
writeValue(obj:any)
:將表單模型中的新值寫入視圖或DOM屬性(如果需要)的方法,它將來自外部的資料寫入到內部的資料模型。資料流向: form model -> component。
registerOnChange(fn:any)
:一種註冊處理程序的方法,當視圖中的某些內容發生變更時應呼叫該處理程序。它具有一個告訴其他表單指令和表單控制項以更新其值的函數。通常在 registerOnChange 中需要保存該事件觸發函數,在資料改變的時候,可以透過呼叫事件觸發函數通知外部資料變了,同時可以將修改後的資料作為參數傳遞出去。資料流向: component -> form model。
registerOnTouched(fn: any)
:註冊 onTouched 事件,基本上同 registerOnChange ,只是函數用來通知表單元件已經處於 touched 狀態,改變綁定的 FormControl 的內部狀態。狀態變更: component -> form model。
setDisabledState(isDisabled: boolean)
:當呼叫FormControl 變更狀態的API 時得表單狀態變為Disabled 時呼叫setDisabledState() 方法,以通知自訂表單元件目前表單的讀取寫狀態。狀態變更: form model -> component。
#建置控制項框架
@Component({<br/> selector: 'app-test-control-value-accessor',<br/> templateUrl: './test-control-value-accessor.component.html',<br/> providers: [{<br/> provide: NG_VALUE_ACCESSOR,<br/> useExisting: forwardRef(() => TestControlValueAccessorComponent),<br/> multi: true<br/> }]<br/>})<br/>export class TestControlValueAccessorComponent implements ControlValueAccessor {<br/><br/> _counterValue = 0;<br/> <br/> private onChange = (_: any) => {};<br/><br/> constructor() { }<br/><br/> get counterValue() {<br/> return this._counterValue;<br/> }<br/><br/> set counterValue(value) {<br/> this._counterValue = value;<br/> // 触发 onChange,component 内部的值同步到 form model<br/> this.onChange(this._counterValue);<br/> }<br/><br/> increment() {<br/> this.counterValue++;<br/> }<br/><br/> decrement() {<br/> this.counterValue--;<br/> }<br/><br/> // form model 的值同步到 component 内部<br/> writeValue(obj: any): void {<br/> if (obj !== undefined) {<br/> this.counterValue = obj;<br/> }<br/> }<br/><br/> registerOnChange(fn: any): void {<br/> this.onChange = fn;<br/> }<br/><br/> registerOnTouched(fn: any): void { }<br/><br/> setDisabledState?(isDisabled: boolean): void { }<br/><br/>}<br/>
註冊ControlValueAccessor
為了獲得ControlValueAccessor
用於表單控件,Angular 內部將注入在NG_VALUE_ACCESSOR
令牌上註冊的所有值,這是將控製本身註冊到DI
框架成為一個可以讓表單存取其值的控制項。因此,我們需要做的就是NG_VALUE_ACCESSOR
使用我們自己的值存取器實例(這是我們的元件)來擴充 multi-provider 。所以設定 multi: true
,是宣告這個 token
對應的類別很多,分散在各處。
這裡我們必須使用 useExisting
,因為TestControlValueAccessorComponent
可能在使用它的元件中被其建立為指令依賴項。這就得用到 forwardRef
了,這個函數允許我們引用一個尚未定義的物件。
@Component({<br/> ...<br/> providers: [<br/> { <br/> provide: NG_VALUE_ACCESSOR,<br/> useExisting: forwardRef(() => TestControlValueAccessorComponent ),<br/> multi: true<br/> }<br/> ]<br/>})<br/>export class TestControlValueAccessorComponent implements ControlValueAccessor {<br/> ...<br/>}<br/>
控制項介面
<div class="panel panel-primary"><br/> <div class="panel-heading">自定义控件</div><br/> <div class="panel-body"><br/> <button (click)="increment()">+</button><br/> {{counterValue}}<br/> <button (click)="decrement()">-</button><br/> </div><br/></div><br/>
#在表單中使用
<div class="constainer"><br/> <form #form="ngForm"><br/> <app-test-control-value-accessor name="message" [(ngModel)]="message"></app-test-control-value-accessor><br/> <button type="button" (click)="submit(form.value)">Submit</button><br/> </form><br/> <pre class="brush:php;toolbar:false">{{ message }}
@Component({<br/> selector: 'app-root',<br/> templateUrl: './app.component.html',<br/> styleUrls: ['./app.component.css']<br/>})<br/>export class AppComponent {<br/><br/> message = 5;<br/><br/> submit(value: any): void {<br/> console.log(value);<br/> }<br/><br/>}<br/>
https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular- 2.html
https://almerosteyn.com/2016/04/linkup-custom-control-to-ngcontrol-ngmodel
## https://juejin.im/post/597176886fb9a06ba4746d15
https://github.com/shhdgit/blogs/issues/11
更多程式相關知識,請造訪:程式設計影片! !
以上是詳解Angular使用ControlValueAccessor實作自訂表單控制項的詳細內容。更多資訊請關注PHP中文網其他相關文章!