Angular 提供了兩種不同的方法來通過表單處理使用者輸入:響應式表單
和模板驅動表單
。【相關教學推薦:《》】
這裡只介紹響應式表單,模板驅動表單請參考官網:
https://angular.cn/guide/forms-overview#setup-in-template-driven-forms
要使用響應式表單控制元件,就要從 @angular/forms
包中匯入 ReactiveFormsModule
,並把它新增到你的 NgModule
的imports
陣列中。如下:app.module.ts
/***** app.module.ts *****/ import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ // other imports ... ReactiveFormsModule ], }) export class AppModule { }
使用表單控制元件有三個步驟。
在你的應用中註冊響應式表單模組。該模組宣告了一些你要用在響應式表單中的指令。
生成一個新的 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
就像FormControl
的範例能讓你控制單個輸入框所對應的控制元件一樣,FormGroup
的範例也能跟蹤一組 FormControl
範例(比如一個表單)的表單狀態。當建立 FormGroup
時,其中的每個控制元件都會根據其名字進行跟蹤。
看下例演示:test.component.ts
、test.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
是一個可注入的服務提供者,它是由 ReactiveFormModule
提供的。只要把它新增到元件的建構函式中就可以注入這個依賴。
FormBuilder
服務有三個方法:control()
、group()
和array()
。這些方法都是工廠方法,用於在元件類中分別生成FormControl
、FormGroup
和FormArray
。
看下例演示: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
服務可以更方便地生成FormControl
、FormGroup
和 FormArray
,而不必每次都手動new
一個新的範例出來。
Validators
類驗證器的完整API列表,參考API手冊https://angular.cn/api/forms/Validators
驗證器(Validators
)函數可以是同步函數,也可以是非同步函數。
FormControl
時把它作為建構函式的第二個引數傳進去。Promise
或 Observable
,它稍後會發出一組驗證錯誤或 null。在範例化 FormControl
時,可以把它們作為第三個引數傳入。出於效能方面的考慮,只有在所有同步驗證器都通過之後,Angular 才會執行非同步驗證器。當每一個非同步驗證器都執行完之後,才會設定這些驗證錯誤。
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其它相關文章!