Angular表單的基本對象為FormControl與FormGroup。 FormControl FormControl代表單個input表單欄位(field),即Angular表單的最小單元。 FormControl封裝了表單欄位的值與狀態(valid, dirty, errors)。 在Typ ...
Angular表單的基本對象為FormControl與FormGroup。
FormControl
FormControl代表單個input表單欄位(field),即Angular表單的最小單元。
FormControl封裝了表單欄位的值與狀態(valid, dirty, errors)。
在TypeScript中創建FormControl:
// create a new FormControl with the value "Nate"
let nameControl = new FormControl("Nate");
let name = nameControl.value; // -> Nate
// now we can query this control for certain values:
nameControl.errors // -> StringMap<string, any> of errors
nameControl.dirty // -> false
nameControl.valid // -> true
在DOM中綁定:
<input type="text" [formControl]="nameControl" />
FormGroup
FormGroup是FormControl集合的包裝器。
let personInfo = new FormGroup({
firstName: new FormControl("Nate"),
lastName: new FormControl("Murray"),
zip: new FormControl("90210")
})
由於FormGroup與FormControl繼承了相同的基類(AbstractControl),這意味著可以像FormControl一樣檢查其值與狀態。
personInfo.value; // -> {
// firstName: "Nate",
// lastName: "Murray",
// zip: "90210"
// }
// now we can query this control group for certain values, which have sensible
// values depending on the children FormControl's values:
personInfo.errors // -> StringMap<string, any> of errors
personInfo.dirty // -> false
personInfo.valid // -> true
Angular中使用表單有FormsModule與ReactiveFormsModule兩種方式。
FormsModule
導入FormsModule後, 將自動對相關視圖中的任意<form>
標簽附加NgForm。
NgForm提供兩樣功能:
- 名為ngForm的FormGroup
- (ngSubmit)
import {
FormsModule
} from '@angular/forms';
// farther down...
@NgModule({
declarations: [
FormsDemoApp,
DemoFormSkuComponent,
// ... our declarations here
],
imports: [
BrowserModule,
FormsModule, // <-- add this
],
bootstrap: [ FormsDemoApp ]
})
class FormsDemoAppModule {}
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-demo-form-sku',
templateUrl: './demo-form-sku.component.html',
styles: []
})
export class DemoFormSkuComponent implements OnInit {
constructor() { }
ngOnInit() {
}
onSubmit(form: any): void {
console.log('you submitted value:', form);
}
}
<div class="ui raised segment">
<h2 class="ui header">Demo Form: Sku</h2>
<form #f="ngForm"
(ngSubmit)="onSubmit(f.value)"
class="ui form">
<div class="field">
<label for="skuInput">SKU</label>
<input type="text"
id="skuInput"
placeholder="SKU"
name="sku" ngModel>
</div>
<button type="submit" class="ui button">Submit</button>
</form>
</div>
#f="ngForm"為視圖創建一個本地變數f,並綁定了ngForm。這樣在視圖的其它地方就可以靈活使用,比如在(ngSubmit)="onSubmit(f.value)中。
在input元素里,單獨的ngModel特性表示一個單向綁定,以及在表單中創建一個名為sku的FormControl,並且自動添加至父級的FormGroup(這裡是form)。
ReactiveFormsModule
這種方式下可以通過FormBuilder幫助創建FormGroup與FormControl。
import {
ReactiveFormsModule
} from '@angular/forms';
// farther down...
@NgModule({
declarations: [
FormsDemoApp,
DemoFormSkuComponent,
// ... our declarations here
],
imports: [
BrowserModule,
ReactiveFormsModule // <-- and this
],
bootstrap: [ FormsDemoApp ]
})
class FormsDemoAppModule {}
import { Component, OnInit } from '@angular/core';
import {
FormBuilder,
FormGroup
} from '@angular/forms';
@Component({
selector: 'app-demo-form-sku-with-builder',
templateUrl: './demo-form-sku-with-builder.component.html',
styles: []
})
export class DemoFormSkuWithBuilderComponent implements OnInit {
myForm: FormGroup;
constructor(fb: FormBuilder) {
this.myForm = fb.group({
'sku': ['ABC123']
});
}
ngOnInit() {
}
onSubmit(value: string): void {
console.log('you submitted value: ', value);
}
}
<div class="ui raised segment">
<h2 class="ui header">Demo Form: Sku with Builder</h2>
<form [formGroup]="myForm"
(ngSubmit)="onSubmit(myForm.value)"
class="ui form">
<div class="field">
<label for="skuInput">SKU</label>
<input type="text"
id="skuInput"
placeholder="SKU"
[formControl]="myForm.controls['sku']">
</div>
<button type="submit" class="ui button">Submit</button>
</form>
</div>
視圖中通過[formGroup]="myForm"綁定已創建的FormGroup,同時onSubmit也改為myForm.value。
而對於input元素,現在藉由[formControl]="myForm.controls['sku']"方式綁定已創建的FormControl。
驗證
向一個FormControl添加驗證器很簡單,只需要將其傳入第二個參數。
let control = new FormControl('sku', Validators.required);
如果是FormBuilder的話,可以使用以下語法:
import { Component } from '@angular/core';
import {
FormBuilder,
FormGroup,
Validators,
AbstractControl
} from '@angular/forms';
@Component({
selector: 'app-demo-form-with-validations-explicit',
templateUrl: './demo-form-with-validations-explicit.component.html',
styles: []
})
export class DemoFormWithValidationsExplicitComponent {
myForm: FormGroup;
sku: AbstractControl;
constructor(fb: FormBuilder) {
this.myForm = fb.group({
'sku': ['', Validators.required]
});
this.sku = this.myForm.controls['sku'];
}
onSubmit(value: string): void {
console.log('you submitted value: ', value);
}
}
<div class="ui raised segment">
<h2 class="ui header">Demo Form: with validations (explicit)</h2>
<form [formGroup]="myForm"
(ngSubmit)="onSubmit(myForm.value)"
class="ui form"
[class.error]="!myForm.valid && myForm.touched">
<div class="field"
[class.error]="!sku.valid && sku.touched">
<label for="skuInput">SKU</label>
<input type="text"
id="skuInput"
placeholder="SKU"
[formControl]="sku">
<div *ngIf="!sku.valid"
class="ui error message">SKU is invalid</div>
<div *ngIf="sku.hasError('required')"
class="ui error message">SKU is required</div>
</div>
<div *ngIf="!myForm.valid"
class="ui error message">Form is invalid</div>
<button type="submit" class="ui button">Submit</button>
</form>
</div>
* 通過myForm的valid屬性值可以判斷所有FormControl是否皆有效。
* [class.error]可以根據FormControl有效與否變更樣式。
* sku.hasError('required'),可以指定特定的驗證要求。
驗證器還能夠按照需求定製:
function skuValidator(control: FormControl): { [s: string]: boolean } {
if (!control.value.match(/^123/)) {
return {invalidSku: true};
}
}
constructor(fb: FormBuilder) {
this.myForm = fb.group({
'sku': ['', Validators.compose([
Validators.required, skuValidator])]
});
<div *ngIf="sku.hasError('invalidSku')"
class="ui error message">SKU must begin with <span>123</span></div>
監察
FormGroup與FormControl都有自己的EventEmitter,可以用於觀察變化。
方式很簡單,使用其valueChanges的subscribe方法進行訂閱。
constructor(fb: FormBuilder) {
this.myForm = fb.group({
'sku': ['', Validators.required]
});
this.sku = this.myForm.controls['sku'];
this.sku.valueChanges.subscribe(
(value: string) => {
console.log('sku changed to:', value);
}
);
this.myForm.valueChanges.subscribe(
(form: any) => {
console.log('form changed to:', form);
}
);
}