angular學習之淺析響應式表單

2022-03-24 13:00:42
本篇文章帶大家繼續angular的學習,瞭解一下angular中的響應式表單,介紹一下全域性註冊響應式表單模組、新增基礎表單控制元件的相關知識,希望對大家有所幫助!

響應式表單

Angular 提供了兩種不同的方法來通過表單處理使用者輸入:響應式表單模板驅動表單。【相關教學推薦:《》】

  • 響應式表單:提供對底層表單物件模型直接、顯式的存取。它們與模板驅動表單相比,更加健壯。如果表單是你的應用程式的關鍵部分,或者你已經在使用響應式表單來構建應用,那就使用響應式表單。
  • 模板驅動表單:依賴模板中的指令來建立和操作底層的物件模型。它們對於嚮應用新增一個簡單的表單非常有用,比如電子郵寄清單登入檔單。

這裡只介紹響應式表單,模板驅動表單請參考官網:

https://angular.cn/guide/forms-overview#setup-in-template-driven-forms

全域性註冊響應式表單模組 ReactiveFormsModule

要使用響應式表單控制元件,就要從 @angular/forms 包中匯入 ReactiveFormsModule,並把它新增到你的 NgModuleimports陣列中。如下:app.module.ts

/***** app.module.ts *****/
import { ReactiveFormsModule } from '@angular/forms';

@NgModule({
  imports: [
    // other imports ...
    ReactiveFormsModule
  ],
})
export class AppModule { }

新增基礎表單控制元件 FormControl

使用表單控制元件有三個步驟。

  • 在你的應用中註冊響應式表單模組。該模組宣告了一些你要用在響應式表單中的指令。

  • 生成一個新的 FormControl 範例,並把它儲存在元件中。

  • 在模板中註冊這個 FormControl

要註冊一個表單控制元件,就要匯入FormControl類並建立一個 FormControl的新範例,將其儲存為類的屬性。如下:test.component.ts

/***** test.component.ts *****/
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-name-editor',
  templateUrl: './name-editor.component.html',
  styleUrls: ['./name-editor.component.css']
})
export class TestComponent {
	// 可以在 FormControl 的建構函式設定初始值,這個例子中它是空字串
  name = new FormControl('');
}

然後在模板中註冊該控制元件,如下:test.component.html

<!-- test.component.html -->
<label>
  Name: <input type="text" [formControl]="name">
</label>
<!-- input 中輸入的值變化的話,這裡顯示的值也會跟著變化 -->
<p>name: {{ name.value }}</p>

FormControl 的其它屬性和方法,參閱 API 參考手冊

https://angular.cn/api/forms/FormControl#formcontrol

把表單控制元件分組 FormGroup

就像FormControl 的範例能讓你控制單個輸入框所對應的控制元件一樣,FormGroup 的範例也能跟蹤一組 FormControl 範例(比如一個表單)的表單狀態。當建立 FormGroup 時,其中的每個控制元件都會根據其名字進行跟蹤。

看下例演示:test.component.tstest.component.html

import { Component } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms'

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css']
})
export class TestComponent implements OnInit {
    constructor() {}

    profileForm = new FormGroup({
      firstName: new FormControl('', [Validators.required,Validators.pattern('[a-zA-Z0-9]*')]),
      lastName: new FormControl('', Validators.required),
    });
	
	onSubmit() {
		// 檢視控制元件組各欄位的值
      console.log(this.profileForm.value)
    }
}
<!-- profileForm 這個 FormGroup 通過 FormGroup 指令繫結到了 form 元素,在該模型和表單中的輸入框之間建立了一個通訊層 -->
<!-- FormGroup 指令還會監聽 form 元素髮出的 submit 事件,並行出一個 ngSubmit 事件,讓你可以繫結一個回撥函數。 -->
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
    <label>
<!-- 由 FormControlName 指令把每個輸入框和 FormGroup 中定義的表單控制元件 FormControl 繫結起來。這些表單控制元件會和相應的元素通訊 -->
      First Name: <input type="text" formControlName="firstName">
    </label>
    <label>
      Last Name: <input type="text" formControlName="lastName">
    </label>
    <button type="submit" [disabled]="!profileForm.valid">Submit</button>
  </form>

  <p>{{ profileForm.value }}</p>
  <!-- 控制元件組的狀態: INVALID 或 VALID -->
  <p>{{ profileForm.status }}</p>	
  <!-- 控制元件組輸入的值是否為有效值: true 或 false-->
  <p>{{ profileForm.valid }}</p>
  <!-- 是否禁用: true 或 false-->
  <p>{{ profileForm.disabled }}</p>

FormGroup 的其它屬性和方法,參閱 API 參考手冊

https://angular.cn/api/forms/FormGroup#formgroup

使用更簡單的 FormBuilder 服務生成控制元件範例

在響應式表單中,當需要與多個表單打交道時,手動建立多個表單控制元件範例會非常繁瑣。FormBuilder服務提供了一些便捷方法來生成表單控制元件。FormBuilder在幕後也使用同樣的方式來建立和返回這些範例,只是用起來更簡單。

FormBuilder 是一個可注入的服務提供者,它是由 ReactiveFormModule 提供的。只要把它新增到元件的建構函式中就可以注入這個依賴。

FormBuilder服務有三個方法:control()group()array()。這些方法都是工廠方法,用於在元件類中分別生成FormControlFormGroupFormArray

看下例演示:test.component.ts

import { Component } from '@angular/core';
// 1、匯入 FormBuilder
import { FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css']
})
export class TestComponent {
	// 2、注入 FormBuilder 服務
    constructor(private fb: FormBuilder) { }
    ngOnInit() { }

    profileForm = this.fb.group({
      firstName: ['', [Validators.required, Validators.pattern('[a-zA-Z0-9]*')]],
      lastName: ['', Validators.required],
    });
    // 相當於
    // profileForm = new FormGroup({
    //   firstName: new FormControl('', [Validators.required,Validators.pattern('[a-zA-Z0-9]*')]),
    //   lastName: new FormControl('', Validators.required),
    // });

    onSubmit() {
      console.log(this.profileForm.value)
      console.log(this.profileForm)
    }
}

對比可以發現,使用FormBuilder服務可以更方便地生成FormControlFormGroupFormArray,而不必每次都手動new一個新的範例出來。

表單驗證器 Validators

Validators類驗證器的完整API列表,參考API手冊

https://angular.cn/api/forms/Validators

驗證器(Validators)函數可以是同步函數,也可以是非同步函數。

  • 同步驗證器:這些同步函數接受一個控制元件範例,然後返回一組驗證錯誤或 null。你可以在範例化一個 FormControl 時把它作為建構函式的第二個引數傳進去。
  • 非同步驗證器 :這些非同步函數接受一個控制元件範例並返回一個 PromiseObservable,它稍後會發出一組驗證錯誤或 null。在範例化 FormControl 時,可以把它們作為第三個引數傳入。

出於效能方面的考慮,只有在所有同步驗證器都通過之後,Angular 才會執行非同步驗證器。當每一個非同步驗證器都執行完之後,才會設定這些驗證錯誤。

驗證器Validators類的API

https://angular.cn/api/forms/Validators

class Validators {
  static min(min: number): ValidatorFn		// 允許輸入的最小數值
  static max(max: number): ValidatorFn		// 最大數值
  static required(control: AbstractControl): ValidationErrors | null	// 是否必填
  static requiredTrue(control: AbstractControl): ValidationErrors | null
  static email(control: AbstractControl): ValidationErrors | null	// 是否為郵箱格式
  static minLength(minLength: number): ValidatorFn		// 最小長度
  static maxLength(maxLength: number): ValidatorFn		// 最大長度
  static pattern(pattern: string | RegExp): ValidatorFn	// 正則匹配
  static nullValidator(control: AbstractControl): ValidationErrors | null	// 什麼也不做
  static compose(validators: ValidatorFn[]): ValidatorFn | null
  static composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn | null
}

內建驗證器函數

要使用內建驗證器,可以在範例化FormControl控制元件的時候新增

import { Validators } from '@angular/forms';
...
ngOnInit(): void {
  this.heroForm = new FormGroup({
  // 範例化 FormControl 控制元件
    name: new FormControl(this.hero.name, [
      Validators.required,	// 驗證,必填
      Validators.minLength(4),	// 長度不小於4
      forbiddenNameValidator(/bob/i) // 自定義驗證器
    ]),
    alterEgo: new FormControl(this.hero.alterEgo),
    power: new FormControl(this.hero.power, Validators.required)
  });
}
get name() { return this.heroForm.get('name'); }

get power() { return this.heroForm.get('power'); }

自定義驗證器

自定義驗證器的內容請參考API手冊

https://angular.cn/guide/form-validation

有時候內建的驗證器並不能很好的滿足需求,比如,我們需要對一個表單進行驗證,要求輸入的值只能為某一個陣列中的值,而這個陣列中的值是隨程式執行實時改變的,這個時候內建的驗證器就無法滿足這個需求,需要建立自定義驗證器。

  • 在響應式表單中新增自定義驗證器。在上面內建驗證器一節中有一個forbiddenNameValidator函數如下:

    import { Validators } from '@angular/forms';
    ...
    ngOnInit(): void {
      this.heroForm = new FormGroup({
        name: new FormControl(this.hero.name, [
          Validators.required,
          Validators.minLength(4),
          // 1、新增自定義驗證器
          forbiddenNameValidator(/bob/i)
        ])
      });
    }
    // 2、實現自定義驗證器,功能為禁止輸入帶有 bob 字串的值
    export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
      return (control: AbstractControl): ValidationErrors | null => {
        const forbidden = nameRe.test(control.value);
        // 3、在值有效時返回 null,或無效時返回驗證錯誤物件
        return forbidden ? {forbiddenName: {value: control.value}} : null;
      };
    }

    驗證器在值有效時返回 null,或無效時返回驗證錯誤物件。 驗證錯誤物件通常有一個名為驗證祕鑰(forbiddenName)的屬性。其值為一個任意詞典,你可以用來插入錯誤資訊({name})。

  • 在模板驅動表單中新增自定義驗證器。要為模板新增一個指令,該指令包含了 validator 函數。同時,該指令需要把自己註冊成為NG_VALIDATORS的提供者。如下所示:

    // 1、匯入相關類
    import { NG_VALIDATORS, Validator, AbstractControl, ValidationErrors } from '@angular/forms';
    import { Input } from '@angular/core'
    
    @Directive({
      selector: '[appForbiddenName]',
      // 2、註冊成為 NG_VALIDATORS 令牌的提供者
      providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true}]
    })
    export class ForbiddenValidatorDirective implements Validator {
      @Input('appForbiddenName') forbiddenName = '';
      // 3、實現 validator 介面,即實現 validate 函數
      validate(control: AbstractControl): ValidationErrors | null {
      	// 在值有效時返回 null,或無效時返回驗證錯誤物件
        return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)
                                  : null;
      }
    }
    // 4、自定義驗證函數
    export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
      return (control: AbstractControl): ValidationErrors | null => {
        const forbidden = nameRe.test(control.value);
        // 3、在值有效時返回 null,或無效時返回驗證錯誤物件
        return forbidden ? {forbiddenName: {value: control.value}} : null;
      };
    }

    注意,自定義驗證指令是用 useExisting 而不是 useClass 來範例化的。如果用useClass來代替 useExisting,就會註冊一個新的類範例,而它是沒有forbiddenName 的。

    <input type="text" required appForbiddenName="bob" [(ngModel)]="hero.name">

更多程式設計相關知識,請存取:!!

以上就是angular學習之淺析響應式表單的詳細內容,更多請關注TW511.COM其它相關文章!