Angular 響應式表單之表單分組

一、案例需求

表單提交,表單所有校驗成功才能提交,當表單校驗錯誤,表單邊框變紅,同時有錯誤提示信息,有重置功能git

二、名詞解釋

在分析代碼以前,首先明確 FormControl、formControl、formControlName、FormGroup、formGroup、formGroupName、FormArray、formArray、formArrayName 都是什麼意思以及它們的用法。github

2.一、FormControl

  • FormControl:跟蹤獨立表單控件的值和驗證狀態。它和 FormGroup 和 FormArray 是 Angular 表單的三大基本構造塊之一。它擴展了 AbstractControl 類,並實現了關於訪問值、驗證狀態、用戶交互和事件的大部分基本功能。

當使用響應式表單時,FormControl 類是最基本的構造塊。要註冊單個的表單控件,在組件中導入 FormControl 類,並建立一個 FormControl 的新實例,把它保存在類的某個屬性中。數組

export class AppComponent implements OnInit {
    const control = new FormControl('', Validators.required);
    console.log(control.value);      // ''
    console.log(control.status);     // 'INVALID'
}

在組件類中建立了控件以後,還要把它和模板中的一個表單控件關聯起來,爲表單控件添加 formControl 綁定。ui

<label>
  Name:
  <input type="text" [formControl]="name">
</label>
  • formControl:是一個輸入指令,接受 FormControl 的實例,在模版中使用。
  • formControlName: 也是輸入指令,可是它接受的是一個字符串,同 formGroup 指令配合使用。
<div>
  <input type="text" [formControl]="myForm.controls.firstName"/>
  <input type="text" [formControl]="myForm.controls.lastName"/>
  <input type="text" [formControl]="myForm.controls.email"/>
  <input type="text" [formControl]="myForm.controls.title"/>
</div>

//等同於

<div [formGroup]="myForm">
  <input type="text" formControlName="firstName"/>
  <input type="text" formControlName="lastName"/>
  <input type="text" formControlName="email"/>
  <input type="text" formControlName="title"/>
</div>

2.二、FormGroup

  • FormGroup:跟蹤一組 FormControl 實例的值和有效性狀態

FormGroup 把每一個子 FormControl 的值聚合進一個對象,它的 key 是每一個控件的名字。它經過歸集其子控件的狀態值來計算出本身的狀態。若是組中的任何一個控件是無效的,那麼整個組就是無效的。this

2.三、FormArray

  • FormArray:跟蹤一個控件數組的值和有效性狀態

FormArray 聚合了數組中每一個表單控件的值。它會根據其全部子控件的狀態總結出本身的狀態。若是 FromArray 中的任何一個控件是無效的,那麼整個數組也會變成無效的。code

  • FormControl、FormGroup、FormArray 類 用法一致
  • formControl、formGroup、formArray 輸入指令 值爲對應類的實例 用法一致
  • formControlName、formGroupName、formArrayName 輸入指令 值爲字符串 用法一直

三、代碼分析

fromGroup 能夠然咱們對錶單內容進行分組,方便咱們在語義上區分不一樣類型的輸入,本例中,地址細分爲「省」、「市」、「區」。orm

this.formGroup = this.fb.group({
      name: ['', nameValidator()],
      age: ['', ageValidator()],
      sex: ['', sexValidator()],
      address: this.fb.group({
        province: ['', requiredValidator('請輸入省')],
        city: ['', requiredValidator('請輸入市')],
        district: ['', requiredValidator('請輸入區')]
      })
    });

address 此時不是 fromControl 而是 formGroup。對象

<div class="form-group"
    formGroupName="address">
    <label>地址:</label>
    <div>
      <label>省:</label>
      <input type="text"
        formControlName="province">
      <p>{{errorMessage('province')}}</p>
    </div>
    <div>
      <label>市:</label>
      <input type="text"
        formControlName="city">
      <p>{{errorMessage('city')}}</p>
    </div>
    <div>
      <label>區:</label>
      <input type="text"
        formControlName="district">
      <p>{{errorMessage('district')}}</p>
    </div>
  </div>

在獲取 省市區的 formControl 時,能夠經過這樣獲取事件

// 太複雜了
this.formGroup.controls['address'].controls['province'];

// 一樣複雜
this.formGroup.get('address').controls['province'];

// 還好
this.formGroup.get(['address', 'province']);

第三種方式雖然簡單,可是不夠完美,get方法不能一步到位,必須同時傳入 formGroupName 和 formControlName。所以在查看單個表單是否有錯誤信息時,必須先判斷 formControlName 是子組件仍是孫子組件。ci

errorMessage(formControlName: string): string {

    let control: AbstractControl;

    if (this.formGroup.contains(formControlName)) {
      control = this.formGroup.get(formControlName);
    } else {
      control = this.formGroup.get(['address', formControlName]);
    }
    return ((control.touched || control.dirty) && control.invalid) ? control.errors.message : '';
  }

contains方法:檢查組內是否有一個具備指定名字的已啓用的控件,存在返回 true,不存在返回 false。

相關文章
相關標籤/搜索