Angular表单中的FormControl、FormGroup、FormBuilder、FormArray
要使用响应式表单,首先需要在@angular/forms包导入ReactiveFormsModule,并把它放到ngModule的imports数组中去。
app.module.ts
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
ReactiveFormsModule, //<==
CommonModule
],
...
})
如果要获得control,还要在component中加入
@Component({
...
selector: 'app-test-array',
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TestArrayComponent),
multi: true,
}]
})
export class TestArrayComponent{
...
}
1、FormControl
FormControl封装了字段的值和状态,比如是否有效、是否脏(被修改过)、是否有错误等等 test-control.component.ts
import { Component, OnInit } from '@angular/core';
import {FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-test-control',
templateUrl: './test-control.component.html',
styleUrls: ['./test-control.component.css'],
})
export class TestControlComponent{
outside = new FormControl('xxxx', [Validators.required])
getValue(){
console.log(this.outside.value);
}
}
test-control.component.html
<div>
测试control:
<span *ngIf="outside?.invalid">不能为空 </span>
<input [formControl]="outside" placeholder="Last name">
<button (click)="getValue()">getvalue</button>
</div>
2、FormGroup
test-group.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { checkNameValidator } from '../myname.validator';
@Component({
selector: 'app-test-group',
templateUrl: './test-group.component.html',
styleUrls: ['./test-group.component.css']
})
export class TestGroupComponent{
form: FormGroup = new FormGroup({
first: new FormControl('lili', {
validators: [Validators.required, Validators.maxLength(5)],
asyncValidators: checkNameValidator(),
updateOn: 'blur'
}),
last: new FormControl({value: 'xxx', disabled: true, })
})
onSubmit(): void{
console.log(this.form.value);
}
get first(): any {
return this.form.get('first');
}
setValue() {
this.form.setValue({first: 'Carson', last: 'Drew'});
}
patchValue(){
this.form.patchValue({first: 'huanggou' })
}
getValue(){
console.log(this.form.getRawValue(), this.form.value);
}
reset(){
this.form.reset();
}
}
test-group.component.html
<div>
测试group:
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div *ngIf="first?.invalid"> Name is too short. </div>
<div *ngIf="first.errors?.checkName">UserName is exist! </div>
<input formControlName="first" placeholder="First name">
<input formControlName="last" placeholder="Last name">
<button type="submit">Submit</button>
</form>
<button (click)="setValue()">Set preset value</button>
<button (click)="patchValue()">patchValue</button>
<button (click)="reset()">Set reset value</button>
<button (click)="getValue()">getvalue</button>
</div>
注意点:
-
在模板中通过[formGroup]="form"指令,管理一个表单组。使用formControlName="name"控制表单元素,只能用在formGroup指令内部。
-
form.get('last')获取FormControl实例。
-
getRawValue()包括所有已禁用的控件。用value属性获取组中的值时,会从FormGroup中排除所有已禁用的控件。
-
setValue()必须传入全部的属性,缺少任意一个属性控制台会报错。patchValue()修改部分属性的值。
3、FormArray
test-array.component.ts
import { Component, forwardRef, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-test-array',
templateUrl: './test-array.component.html',
styleUrls: ['./test-array.component.css'],
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TestArrayComponent),
multi: true,
}]
})
export class TestArrayComponent{
address: FormArray;
info: FormGroup;
constructor(private fb: FormBuilder) {
this.address = this.fb.array([]);
this.info = this.fb.group({
address: this.address
});
}
//添加地址
addAddress() {
this.address.push(new FormGroup({
provience: new FormControl(),
city: new FormControl()
}));
}
//移除地址
removeAddress(index) {
this.address.removeAt(index);
}
//获取表单值
getInfo() {
console.log(this.info.value);
}
}
test-array.component.html
<div [formGroup]="info">
<div>
<div>Address</div>
<div><button (click)="addAddress()">Add</button></div>
<div *ngFor="let address of info.get('address').controls;let idx=index">
<p>
Provience:<input [formControl]="address.get('provience')">
City:<input [formControl]="address.get('city')">
<button (click)="removeAddress(idx)">Remove</button>
</p>
</div>
</div>
</div>
<button (click)="getInfo()">Get Info</button>
group -> array -> group={provience,city}
4、FormBuilder
使用户指定的配置创建AbstractControl。它提供了一个语法糖,用来简化FormControl、FormGroup 或 FormArray 实例的创建过程。它会减少构建复杂表单时所需的样板代码的数量。
test-builder.component.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-test-builder',
templateUrl: './test-builder.component.html',
styleUrls: ['./test-builder.component.css'],
})
export class TestBuilderComponent {
control: FormControl;
group: FormGroup;
constructor(private fb: FormBuilder){
this.control = fb.control({
value: 'xx' , disabled: true
})
this.group = fb.group({
username: ['jack', Validators.required],
password: ['', Validators.required]
})
}
}
test-builder.component.html
<div>
测试builder:
<input [formControl]="control" placeholder="First">
<div [formGroup]="group">
<label>Name:</label>
<input type="text" formControlName="username">
<div [style.color]="'red'" *ngIf="group.get('username').invalid && (group.get('username').touched || group.get('username').dirty)">
<p *ngIf="group.get('username').errors.required">UserName can not be empty!</p>
<p *ngIf="group.get('username').errors.checkName">UserName is exist!</p>
</div>
<label>Password:</label>
<input type="password" formControlName="password">
<div [style.color]="'red'" *ngIf="group.get('password').invalid && (group.get('password').touched || group.get('password').dirty)">
<p *ngIf="group.get('password').errors.required">password can not be empty!</p>
<p *ngIf="group.get('password').errors.password">password is illegal!</p>
</div>
</div>
</div>