
如何快速入門VUE3.0:進入學習
Angular 提供了兩種不同的方法來透過表單處理使用者輸入:响应式表单和模板驱动表单。 【相關教學推薦:《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: 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): ValidatorFternn // 最大長度stating | 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">