Angular 響應式表單之表單分組

1、案例需求

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

2、名詞解釋

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

2.1、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 綁定。

<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>

FormGroup、FormArray的用法同 FormControl 類似。

3、代碼分析

fromGroup 可以然我們對錶單內容進行分組,方便我們在語義上區分不同類型的輸入,本例中,地址細分爲“省”、“市”、“區”。

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 是子組件還是孫子組件。

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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章