溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Angular如何使用ControlValueAccessor實(shí)現(xiàn)自定義表單控件

發(fā)布時(shí)間:2021-04-28 09:56:51 來源:億速云 閱讀:362 作者:小新 欄目:web開發(fā)

這篇文章主要介紹了Angular如何使用ControlValueAccessor實(shí)現(xiàn)自定義表單控件,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

本篇文章給大家介紹一下Angular使用ControlValueAccessor實(shí)現(xiàn)自定義表單控件的方法。有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)大家有所幫助。

Angular: [ControlValueAccessor] 自定義表單控件


我們?cè)趯?shí)際開發(fā)中,通常會(huì)遇到各種各樣的定制化功能,會(huì)遇到有些組件會(huì)與 Angular 的表單進(jìn)行交互,這時(shí)候我們一般會(huì)從外部傳入一個(gè) FormGroup 對(duì)象,然后在組件的內(nèi)部寫相應(yīng)的邏輯對(duì) Angular 表單進(jìn)行操作。如果我們只是對(duì)表單中的一個(gè)項(xiàng)進(jìn)行定制,將整個(gè)表單對(duì)象傳入顯然不合適,并且組件也會(huì)顯得臃腫。

<form [formGroup]="simpleForm">                                
  <other-component [form]="simpleForm"></other-component>        
</form>

那么,我們能不能像原生表單一樣去使用這些自定義組件呢?目前,開源組件 ng-zorro-antd 表單組件能和原生表單一樣使用 formControlName 這個(gè)屬性,這類組件就叫自定義表單組件。

如何實(shí)現(xiàn)自定義表單控件

在 Angular 中,使用 ControlValueAccessor 可以實(shí)現(xiàn)組件與外層包裹的 form 關(guān)聯(lián)起來。

ControlValueAccessor是用于處理以下內(nèi)容的接口:

  • 將表單模型中的值寫入視圖/ DOM

  • 在視圖/ DOM更改時(shí)通知其他表單指令和控件

ControlValueAccessor

ControlValueAccessor 接口定義了四個(gè)方法:

writeValue(obj: any): void

registerOnChange(fn: any): void

registerOnTouched(fn: any): void

setDisabledState(isDisabled: boolean)?: void

writeValue(obj:any):將表單模型中的新值寫入視圖或DOM屬性(如果需要)的方法,它將來自外部的數(shù)據(jù)寫入到內(nèi)部的數(shù)據(jù)模型。數(shù)據(jù)流向: form model -> component。

registerOnChange(fn:any):一種注冊(cè)處理程序的方法,當(dāng)視圖中的某些內(nèi)容發(fā)生更改時(shí)應(yīng)調(diào)用該處理程序。它具有一個(gè)告訴其他表單指令和表單控件以更新其值的函數(shù)。通常在 registerOnChange 中需要保存該事件觸發(fā)函數(shù),在數(shù)據(jù)改變的時(shí)候,可以通過調(diào)用事件觸發(fā)函數(shù)通知外部數(shù)據(jù)變了,同時(shí)可以將修改后的數(shù)據(jù)作為參數(shù)傳遞出去。數(shù)據(jù)流向: component -> form model。

registerOnTouched(fn: any):注冊(cè) onTouched 事件,基本同 registerOnChange ,只是該函數(shù)用于通知表單組件已經(jīng)處于 touched 狀態(tài),改變綁定的 FormControl 的內(nèi)部狀態(tài)。狀態(tài)變更: component -> form model。

setDisabledState(isDisabled: boolean):當(dāng)調(diào)用 FormControl 變更狀態(tài)的 API 時(shí)得表單狀態(tài)變?yōu)?Disabled 時(shí)調(diào)用 setDisabledState() 方法,以通知自定義表單組件當(dāng)前表單的讀寫狀態(tài)。狀態(tài)變更: form model -> component。

如何使用 ControlValueAccessor

搭建控件框架

@Component({
  selector: 'app-test-control-value-accessor',
  templateUrl: './test-control-value-accessor.component.html',
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => TestControlValueAccessorComponent),
    multi: true
  }]
})
export class TestControlValueAccessorComponent implements ControlValueAccessor {

  _counterValue = 0;
 
  private onChange = (_: any) => {};

  constructor() { }

  get counterValue() {
    return this._counterValue;
  }

  set counterValue(value) {
    this._counterValue = value;
    // 觸發(fā) onChange,component 內(nèi)部的值同步到 form model
    this.onChange(this._counterValue);
  }

  increment() {
    this.counterValue++;
  }

  decrement() {
    this.counterValue--;
  }

  // form model 的值同步到 component 內(nèi)部
  writeValue(obj: any): void {
    if (obj !== undefined) {
      this.counterValue = obj;
    }
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void { }

  setDisabledState?(isDisabled: boolean): void { }

}

注冊(cè) ControlValueAccessor

為了獲得 ControlValueAccessor 用于表單控件,Angular 內(nèi)部將注入在 NG_VALUE_ACCESSOR 令牌上注冊(cè)的所有值,這是將控件本身注冊(cè)到 DI 框架成為一個(gè)可以讓表單訪問其值的控件。因此,我們需要做的就是NG_VALUE_ACCESSOR 使用我們自己的值訪問器實(shí)例(這是我們的組件)擴(kuò)展 multi-provider 。所以設(shè)置 multi: true,是聲明這個(gè) token 對(duì)應(yīng)的類很多,分散在各處。

這里我們必須使用 useExisting,因?yàn)?code>TestControlValueAccessorComponent 可能在使用它的組件中被其創(chuàng)建為指令依賴項(xiàng)。這就得用到 forwardRef 了,這個(gè)函數(shù)允許我們引用一個(gè)尚未定義的對(duì)象。

@Component({
  ...
  providers: [
    { 
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => TestControlValueAccessorComponent ),
      multi: true
    }
  ]
})
export class TestControlValueAccessorComponent implements ControlValueAccessor {
  ...
}

控件界面

  • test-control-value-accessor.component.html

<div class="panel panel-primary">
  <div class="panel-heading">自定義控件</div>
  <div class="panel-body">
    <button (click)="increment()">+</button>
    {{counterValue}}
    <button (click)="decrement()">-</button>
  </div>
</div>

在表單中使用

  • app.component.html

<div class="constainer">
  <form #form="ngForm">
    <app-test-control-value-accessor name="message" [(ngModel)]="message"></app-test-control-value-accessor>
    <button type="button" (click)="submit(form.value)">Submit</button>
  </form>
  <pre>{{ message }}</pre>
</div>
  • app.component.ts

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  message = 5;

  submit(value: any): void {
    console.log(value);
  }

}

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Angular如何使用ControlValueAccessor實(shí)現(xiàn)自定義表單控件”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI