Angular表单中的FormControl、FormGroup、FormBuilder、FormArray
要使用响应式表单,首先需要在@angular/forms包中导入ReactiveFormsModule,并把它放到ngModule的imports数组中去。
login.module.ts
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
ReactiveFormsModule, //<==
CommonModule
],
...
})
1 FormControl
FormControl是为单个表单控件提供支持的类,它是Angular表单中的最基本的构造块
FormControl封装了这些字段的值和状态,比如是否有效、是否脏(被修改过)或是否有错误等。还提供了一系列公共API。
1.1 构造函数
创建新的FormControl示例。
constructor(formState: any = null, validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[])
参数 | 数据类型 | 说明 |
---|---|---|
formState | any | 使用一个初始值或定义了初始值和禁用状态的对象初始化该控件。可选,默认值为null |
validatorOrOpts | ValidatorFn或AbstractControlOptions或ValidatorFn[] | 一个同步验证器函数或其数组,或者一个包含验证函数和验证触发器的AbstractControlOptions对象。可选,默认值为undefined |
asyncValidator | AsyncValidatorFn或AsyncValidatorFn[] | 一个异步验证器函数或其数组。可选,默认值为undefined |
具体示例如下。
1.1.1 用一个初始值初始化FormControl
const control = new FormControl('somevalue');
console.log(control.value); //'some value'
1.1.2 用一个表单状态对象初始化控件
这里用到的是value和disabled键
const control = new FormControl({value:'n/a',disabled:true});
console.log(control.value); //'n/a'
console.log(control.status); //'DISABLED'
具体使用示例如下。
login.component.html
<div>
<label>Name:</label>
<input type="text" [formControl]="username">
</div>
<div>
<label>Password:</label>
<input type="password" [formControl]="password">
</div>
<button type="submit" (click)="onSubmit()">登录</button>
login.conponent.ts
import { FormControl } from '@angular/forms';
import { Component } from '@angular/core';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent {
username:FormControl = new FormControl('Tom');
password:FormControl = new FormControl();
onSubmit() {
console.log(this.username.value, this.password.value);
}
}
- formControl是一个指令,它接收一个FormControl的实例,来管理表单元素。
- 构造FormControl的实例时,第一个参数是表单元素的初始值,也可传入一个对象{value:‘Tom’,disabled:true},里面可以包含表单元素的状态,如是否禁用等。
- 在提交时,可以通过this.name.value获取表单元素的值。
- 当我们需要在元素值改变时做一些事情,可以订阅对应控件的valueChanges事件。
this.name.valueChanges.subscribe(() => {
// do something...
console.log(this.name);
});
1.1.3 用一个同步验证器初始化控件
const control = new FormControl('',Validators.required);
console.log(control.value); //''
console.log(control.status); //'INVALID'
具体使用示例如下。
password.validator.ts
export const PasswordValidator = (password?:RegExp): ValidatorFn => {
return (control:AbstractControl): {[key: string]: any} => {
let error = null;
if (password && !password.test(control.value)) {
error = {
password:control.value
}
}
return error;
}
}
login.component.html
<div>
<label>Password:</label>
<input type="password" [formControl]="password">
<div [style.color]="'red'" *ngIf="password.invalid && (password.touched || password.dirty)">
<p *ngIf="password.errors.required">password can not be empty!</p>
<p *ngIf="password.errors.password">password is illegal!</p>
</div>
</div>
login.component.ts
password:FormControl = new FormControl('', [Validators.required, PasswordValidator()]);
- FormControl的第二个参数可以传入一个ValidatorFn对象或者一个包含ValidatorFn对象的数组。
- angular2内置的验证器可以通过Validators取到,如:Validators.required。
- 自定义的验证器只需引用我们在模板驱动型表单中构造的验证器工厂函数(PasswordValidator)生成一个ValidatorFn对象的实例即可。
- FormControl上包含了表单的验证信息,在模板中可以直接使用它。
1.1.4 用一个配置对象初始化控件
const control = new FormControl('',{
validators:Validators.required,
asyncValidators:myAsyncValidator
});
给FormControl添加异步验证器的具体示例如下。
username.validator.ts
const usernameList = [
'jack',
'rose',
'amy',
'tom'
];
export const checkNameValidator = () => {
return (control:AbstractControl) => new Promise(
(resolve, reject) => {
setTimeout(() => {
if (usernameList.indexOf(control.value) >= 0) {
resolve({
'checkName':control.value
});
} else {
resolve(null);
}
}, 2000)
}
);
}
login.component.html
<label>Name:</label>
<input type="text" [formControl]="username">
<div [style.color]="'red'" *ngIf="username.invalid && (username.touched || username.dirty)">
<p *ngIf="username.errors.required">UserName can not be empty!</p>
<p *ngIf="username.errors.checkName">UserName is exist!</p>
</div>
login.component.ts
username:FormControl = new FormControl('jack', Validators.required, checkNameValidator());
- FormControl的第三个参数可以传入一个AsyncValidatorFn对象或者一个包含AsyncValidatorFn对象的数组。
- 异步验证器只需引用我们在模板驱动型表单中构造的验证器工厂函数(checkNameValidator )生成一个AsyncValidatorFn对象的实例即可。
1.1.5 配置该控件,使其在blur事件时更新
把updateOn选项设置为’blur’,可以在发生blur事件时更新。
const control = new FormControl('',{updateOn:'blur'});
1.1.6 配置该控件,使其在发生submit事件时更新
把updateOn选项设置为’submit’,可以在发生submit事件时更新
const control = new FormControl('',{updateOn:'submit'});
1.2 方法
1.2.1 setvalue()
设置该表单控件的新值
setValue(value: any, options: { onlySelf?: boolean; emitEvent?: boolean; emitModelToViewChange?: boolean; emitViewToModelChange?: boolean; } = {}): void
参数 | 数据类型 | 说明 |
---|---|---|
value | any | 控件的新值 |
options | object | 当值发生变化时,该配置项决定如何传播变更以及发出事件。该配置项会传递给updateVauleAndValidity方法。可选,默认值是{} |
options中具体的属性有:
- onlySelf:如果为true,则每次变更只影响该控件本身,不影响其父控件。默认为false。
- emitEvent:如果为true或未提供(默认),则当控件值变化时,statusChanges和valueChanges这两个Observable都会以最近的状态和值发出事件。如果为false,则不会发出事件。
- emitModelToViewChange:如果为true或未提供(默认),则每次都会触发一个onChange事件以更新视图。
- emitViewToModelChange:如果为true或未提供(默认),则每次变化都会触发一个ngModelChange事件以更新模型。
1.2.2 patchValue()
修补控件的值。在FormControl这个层次上,该函数的功能和setValue完全相同。但在FormGroup和FormArray上的patchValue则有不同的行为。
patchValue(value: any, options: { onlySelf?: boolean; emitEvent?: boolean; emitModelToViewChange?: boolean; emitViewToModelChange?: boolean; } = {}): void
参数 | 数据类型 | 说明 |
---|---|---|
value | any | |
options | object | 可选,默认值是{} |
1.2.3 reset()
重置该表单控件,把它标记为pristine和untouched,并把它的值设置为null。
reset(formState: any = null, options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
参数 | 数据类型 | 说明 |
---|---|---|
formState | any | 使用初始值或一个包含初始值和禁用状态的对象来重置该组件。可选,默认值是null |
options | object | 当值发生变化时,该配置项会决定控件如何传播变更以及发出事件。可选,默认值是{} |
options中具体的属性有:
- onlySelf:如果为true,则每次变更只影响该控件本身,不影响其父控件。默认为false。
- emitEvent:如果为true或未提供(默认),则当控件值变化时,statusChanges和valueChanges这两个Observable都会以最近的状态和值发出事件。如果为false,则不会发出事件。
1.2.3.1 把控件重置为初始值
通过传递包含值和禁用状态的独立值或表单状态对象,可以将其重置为特定的表单状态(这是所支持的禁用的两个非计算状态)。
const control = new FormControl('Nancy');
console.log(control.value); //'Nancy'
control.reset('Drew');
console.log(control.value); //'Drew'
1.2.3.2 把控件重置回初始值并禁用
const control = new FormControl('Nancy');
console.log(control.value); //'Nancy'
console.log(control.status); //'VALID'
control.reset({value:'Drew',disabled:true});
console.log(control.value); //'Drew'
console.log(control.status); //'DISABLED'
1.2.4 registerOnChange()
注册变更事件的监听器
registerOnChange(fn: Function): void
参数 | 数据类型 | 说明 |
---|---|---|
fn | Function | 当值变化时,就会调用该方法 |
1.2.5 registerOnDisabledChange()
注册禁用事件的监听器
registerOnDisabledChange(fn: (isDisabled: boolean) => void): void
参数 | 数据类型 | 说明 |
---|---|---|
fn | (isDisabled: boolean) => void | 当禁用状态发生变化时,就会调用该方法 |
2 FormGroup
FormGroup中包含一组FormControl实例,用来管理多个FormControl。它将每个子FormControl的值聚合进一个对象,它的key是每个控件的名字,可以跟踪FormControl组的值和验证状态。FormGroup的状态是归集的所有子控件的状态值计算出来的。
2.1 构造函数
创建一个新的FormGroup实例。
constructor(controls: { [key: string]: AbstractControl; }, validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[])
参数 | 数据类型 | 说明 |
---|---|---|
controls | object | 一组子控件。每个子控件的名字就是它注册时用的key |
validatorOrOpts | ValidatorFn或AbstractControlOptions或ValidatorFn[] | 一个同步验证器函数或其数组,或者一个包含验证函数和验证触发器的AbstractControlOptions对象。可选,默认值是undefined |
asyncValidator | AsyncValidatorFn或AsyncValidatorFn[] | 单个的异步验证器函数或其数组。可选,默认值是undefined |
2.1.1 创建一个带有两个控件的表单组
const form = new FormGroup({
first:new FormControl('Nancy',Validators.minLength(2),
last:new FormControl('Drew')),
});
console.log(form.value); //{first:'Nancy',last:'Drew'}
console.log(form.status); //'VALID'
2.1.2 创建一个具有组级验证器的表单组
当你要根据一个以上子控件的值来决定有效性时,可用第二个参数传入一些组级验证器或用第三个参数传入一些组级异步验证器。
const form = new FormGroup({
password: new FormControl('', Validators.minLength(2)),
passwordConfirm: new FormControl('', Validators.minLength(2)),
}, passwordMatchValidator);
function passwordMatchValidator(g: FormGroup) {
return g.get('password').value === g.get('passwordConfirm').value
? null : {'mismatch': true};
}
像FormControl实例一样,你也可以在配置对象中传入验证器和异步验证器。
const form = new FormGroup({
password: new FormControl('')
passwordConfirm: new FormControl('')
}, { validators: passwordMatchValidator, asyncValidators: otherValidator });
2.1.3 为表单组中的所有空间设置updateOn属性
该选项对象可用来为每个子控件的updateOn属性设置默认值。如果在组级把updateOn设置为’blur’,则所有子控件的默认值也是’blur’,除非这个子控件显式的指令了另一个updateOn值。
const c = new FormGroup({one:new FromControl()},{updateOn:'blur'});
2.2 属性
属性 | 说明 |
---|---|
controls: {[key: string]: AbstractControl;} | 一组子控件。每个子控件的名字就是它注册时用的key |
2.3 方法
2.3.1 registerControl()
向组内的控件列表中注册一个控件,该方法不会更新控件的值或其有效性。
registerControl(name: string, control: AbstractControl): AbstractControl
参数 | 数据类型 | 说明 |
---|---|---|
name | string | 注册到集合中的控件名 |
control | AbstractControl | 提供这个名字对应的控件 |
2.3.2 addControl()
往组内添加一个控件,该方法还会更新控件内值和有效性
addControl(name: string, control: AbstractControl): void
参数 | 数据类型 | 说明 |
---|---|---|
name | string | 注册到集合中的控件名 |
control | AbstractControl | 提供这个名字对应的控件 |
2.3.3 removeControl()
从该组中移除一个控件
removeControl(name: string): void
参数 | 数据类型 | 说明 |
---|---|---|
name | string | 要从集合中移除的控件名 |
2.3.4 setControl()
替换现有控件
setControl(name: string, control: AbstractControl): void
参数 | 数据类型 | 说明 |
---|---|---|
name | string | 要从集合中替换掉的控件名 |
control | AbstractControl | 提供具有指定名称的控件 |
2.3.5 contains()
检查组内是否具有一个指定名字的已启用的控件。对于已禁用的控件返回false,否则返回true。如果你只想检查它是否存在于该组中,请改用get代替。
contains(controlName: string): boolean
参数 | 数据类型 | 说明 |
---|---|---|
controlName | string | 要在集合中检查是否存在的控件名 |
2.3.6 setValue()
设置此FormGroup的值。它接受一个与组结构对应的对象,以控件名作为key。它会进行严格的检查,当设置了不存在或被排出去的控件的值时会失败。
setValue(value: { [key: string]: any; }, options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
参数 | 数据类型 | 说明 |
---|---|---|
value | object | 控件的新值,其结构必须和该组的结构相匹配 |
options | object | 当值变化时,此配置项会决定该控件会如何让传播变更以及发出时间。该配置项会被传给updateValueAndValidity方法。可选,默认值是{} |
options的具体参数为:
- onlySelf:如果为true,则每个变更仅仅影响当前控件,而不会影响父控件。默认为false。
- emitEvent:如果为true会未提供(默认),则当控件值发生变化时,statusChanges和valueChanges这两个Observable分别会以最近的状态和值发出事件。如果为false则不发出事件。
设置表单的完整值
const form = new FormGroup({
first:new FormControl(),
last:new FormControl()
});
console.log(form.value); //{first:null,last:null}
form.setValue({first:'Nancy',last:'Drew'});
console.log(form.value); //{first:'Nancy',last:'Drew'}
2.3.7 patchValue()
修补此FormGroup的值。它接受一个以控件名为key的对象,并尽量把它们的值匹配到组中正确的控件上,它只会替换表单模型中修改过的那些属性。它能接受组的超集和子集而不会抛出错误。
patchValue(value: { [key: string]: any; }, options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
参数 | 数据类型 | 说明 |
---|---|---|
value | object | 与该组的结构匹配的对象 |
options | object | 在修补了该值之后,此配置项会决定控件如何传播变更以及发出事件。该配置项会被传给updateValueAndValidity方法。可选,默认值为{} |
options的具体参数为:
- onlySelf:如果为true,则每个变更仅仅影响当前控件,而不会影响父控件。默认为false。
- emitEvent:如果为true会未提供(默认),则当控件值发生变化时,statusChanges和valueChanges这两个Observable分别会以最近的状态和值发出事件。如果为false则不发出事件。
修补表单组的值
const form = new FormGroup({
first:new FormControl(),
last:new FormControl()
});
console.log(form.value); //{first:null,last:null}
form.setValue({first:'Nancy'});
console.log(form.value); //{first:'Nancy',last:null}
2.3.8 reset()
重置这个FormGroup,把它的各级子控件都标记为pristine和untouched,并把它们的值都设置为null。
也可以传入一个与表单结构相匹配的以控件名为key的Map,来把表单重置为特定的状态。其状态可以是一个单独的值,也可以是一个同时具有值和禁用状态的表单状态对象。
reset(value: any = {}, options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
参数 | 数据类型 | 说明 |
---|---|---|
value | any | 使用一个初始值或包含初始值与禁用状态的对象重置该控件。可选,默认值是{} |
options | object | 当该组被重置时,此配置项会决定控件如何传播变更以及发出事件。该配置项会被传给updateValueAndValidity方法。可选,默认值为{} |
options的具体参数为:
- onlySelf:如果为true,则每个变更仅仅影响当前控件,而不会影响父控件。默认为false。
- emitEvent:如果为true会未提供(默认),则当控件值发生变化时,statusChanges和valueChanges这两个Observable分别会以最近的状态和值发出事件。如果为false则不发出事件。
重置该表单组的值
const form = new FormGroup({
first:new FormControl('first name'),
last:new FormControl('last name')
});
console.log(form.value); //{first:'first name',last:'last name'}
form.reset({first:'name',last:'last name'});
console.log(form.value); //{first:'name',last:'last name'}
重置该表单组的值以及禁用状态
const form = new FormGroup({
first:new FormControl('first name'),
last:new FormControl('last name')
});
console.log(form.value); //{first:'first name',last:'last name'}
form.reset({first:{value:'name',disabled:true},last:'last'});
console.log(form.value); //{first:'name',last:'last name'}
//代码示例来自官方文档,此处不清楚为何未重置成功,可能是两个表单状态格式要书写一致
console.log(this.form.get('first'.status)); //'DISABLED'
2.3.9 getRawValue()
这个FormGroup的聚合值,包括所有已禁用的控件。获取所有控件的值而不管其禁用状态。用value属性获取组中的值时,会从FormGroup中排除所有已禁用的控件。
getRawValue(): any[]
2.4 具体使用示例
login-component.html
<div [formGroup]="info">
<div>
<label>Name:</label>
<input type="text" formControlName="username">
<div [style.color]="'red'" *ngIf="info.get('username').invalid && (info.get('username').touched || info.get('username').dirty)">
<p *ngIf="info.get('username').errors.required">UserName can not be empty!</p>
<p *ngIf="info.get('username').errors.checkName">UserName is exist!</p>
</div>
</div>
<div>
<label>Password:</label>
<input type="password" formControlName="password">
<div [style.color]="'red'" *ngIf="info.get('password').invalid && (info.get('password').touched || info.get('password').dirty)">
<p *ngIf="info.get('password').errors.required">password can not be empty!</p>
<p *ngIf="info.get('password').errors.password">password is illegal!</p>
</div>
</div>
<button type="submit" (click)="onSubmit()">Submit</button>
</div>
login.component.ts
import { checkNameValidator } from '../validators/username.validator';
import { PasswordValidator } from '../validators/password.validator';
import { FormControl, FormGroup, Validator, Validators } from '@angular/forms';
import { Component } from '@angular/core';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent {
info:FormGroup = new FormGroup({
username:new FormControl('jack', Validators.required, checkNameValidator()),
password:new FormControl('', [Validators.required, PasswordValidator()])
});
onSubmit() {
console.log(this.info.value);
}
}
- 构造FormGroup需传入一个包含有FormControl实例的对象。
- 在模板中可以通过[formGroup]="info"指令,管理一个表单组。
- 在包含有formGroup指令的元素的子节点上,可以使用formControlName="name"代替[formControl]="name"来控制表单元素,formControlName指令只能在formGroup指令内部使用。
- 在FormGroup上可以通过info.get(‘name’)获取FormControl实例。
- 在FormGroup上可以通过this.info.value获取表单组的值。
- 在FormGroup上可以通过this.info.setValue(newValue)或this.info.patchValue(newValue)设置FormGroup的值,setValue是修改整个FormGroup的值,传入的值必须包含全部的属性,缺少任意一个属性控制台会报错,用patchValue时,可修改部分属性的值。
- FormGroup内部可以嵌套FormGroup,如Name可能又包含firstName和lastName,此时我们可以构造嵌套的FormGroup。
<div formGroupName="name">
<input type="text" formControlName="first">
<input type="text" formControlName="last">
</div>
info:FormGroup = new FormGroup({
name: new FormGroup({
first:new FormControl(),
last:new FormControl()
})
});
3 FormArray
跟踪每一个控件数组的值和有效特性,控件可以是FormControl、FormGroup或FormArray的实例。它聚合了数组中每个表单控件的值,还会根据其所有子控件的状态总结出自己的状态。
3.1 构造函数
创建一个新的 FormArray 实例
constructor(controls: AbstractControl[], validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[])
参数 | 数据类型 | 说明 |
---|---|---|
controls | AbstractControl[] | 一个子控件数组。在注册后,每个子控件都会有一个指定的索引。 |
validatorOrOpts | ValidatorFn或AbstractControlOptions或ValidatorFn[] | 一个同步验证器函数或其数组,或者一个包含验证函数和验证触发器的 AbstractControlOptions 对象。可选, 默认值是 undefined |
asyncValidator | AsyncValidatorFn或AsyncValidatorFn[] | 单个的异步验证器函数或其数组。可选,默认值是 undefined |
3.1.1创建表单控件的数组
const arr = new FormArray([
new FormControl('Nancy', Validators.minLength(2)),
new FormControl('Drew'),
]);
console.log(arr.value); //['Nancy', 'Drew']
console.log(arr.status); //'VALID'
3.1.2 创建一个带有数组级验证器的表单数组
你可以定义数组级的验证器和异步验证器。当你需要根据一个或多个子控件的值来进行有效性验证时,这很有用。
这两种类型的验证器分别通过第二个和第三个参数或作为配置对象的一部分传进去。
const arr = new FormArray([
new FormControl('Nancy'),
new FormControl('Drew')
], {validators: myValidator, asyncValidators: myAsyncValidator});
3.1.3 为表单数组中的所有控件设置 updateOn 属性
该配置对象可以为每个子控件的updateOn属性设置默认值。如果在数组级把 updateOn 设置为’blur’,则所有子控件的默认值也是’blur’,除非这个子控件显式的指定了另一个 updateOn 值。
const arr = new FormArray([
new FormControl()
], {updateOn: 'blur'});
3.1.4 从表单数组中添加或删除控件
要改变数组中的控件列表,可以使用FormArray本身的push、insert、removeAt 或 clear方法。这些方法能确保表单数组正确的跟踪这些子控件。不要直接修改实例化 FormArray 时传入的那个 AbstractControl 数组,否则会导致奇怪的、非预期的行为,比如破坏变更检测机制。
3.2 属性
属性 | 数据类型 | 说明 |
---|---|---|
controls | AbstractControl[] | 一个子控件数组。在注册后,每个子控件都会有一个指定的索引。 |
length | number | 控件数组的长度。 |
3.3 方法
3.3.1 at()
获取数组中指定index处的AbstractControl。
at(index: number): AbstractControl
参数 | 数据类型 | 说明 |
---|---|---|
index | number | 要获取的控件在数组中的索引 |
3.3.2 push()
在数组的末尾插入一个新的 AbstractControl。
push(control: AbstractControl): void
参数 | 数据类型 | 说明 |
---|---|---|
control | AbstractControl | 要插入的表单控件 |
3.3.3 insert()
在数组中的指定index处插入一个新的 AbstractControl。
insert(index: number, control: AbstractControl): void
参数 | 数据类型 | 说明 |
---|---|---|
index | number | 要插入该控件的索引序号 |
control | AbstractControl | 要插入的表单控件 |
3.3.4 removeAt()
移除数组中指定index处的AbstractControl。
removeAt(index: number): AbstractControl
参数 | 数据类型 | 说明 |
---|---|---|
index | number | 要移除的控件在数组中的索引 |
3.3.5 setControl()
在数组中的指定index处将现有的控件替换成一个新的AbstractControl。
setControl(index: number, control: AbstractControl): void
参数 | 数据类型 | 说明 |
---|---|---|
index | number | 要替换的控件在数组中的索引 |
control | AbstractControl | 要用来替换现有控件的控件 |
3.3.6 setValue()
设置此FormArray的值。它接受一个与组结构对应的对象,以控件名作为key。它会进行严格的检查,当设置了不存在或被排出去的控件的值时会失败。
setValue(value: any[], options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
参数 | 数据类型 | 说明 |
---|---|---|
value | any[] | 要传给这些控件的值的数组 |
options | object | 当值变化时,此配置项会决定该控件会如何让传播变更以及发出时间。该配置项会被传给updateValueAndValidity方法。可选,默认值是{} |
options的具体参数为:
- onlySelf:如果为true,则每个变更仅仅影响当前控件,而不会影响父控件。默认为false。
- emitEvent:如果为true会未提供(默认),则当控件值发生变化时,statusChanges和valueChanges这两个Observable分别会以最近的状态和值发出事件。如果为false则不发出事件。
设置表单的完整值
const arr = new FormArray({
new FormControl(),
new FormControl()
});
console.log(arr.value); //[null,null]
arr.setValue(['Nancy','Drew']);
console.log(form.value); //['Nancy','Drew']
3.3.7 patchValue()
修补此FormArray的值。它接受一个以控件名为key的对象,并尽量把它们的值匹配到组中正确的控件上,它只会替换表单模型中修改过的那些属性。它能接受组的超集和子集而不会抛出错误。
patchValue(value: any[], options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
参数 | 数据类型 | 说明 |
---|---|---|
value | any[] | 由各个控件的值组成的数组 |
options | object | 在修补了该值之后,此配置项会决定控件如何传播变更以及发出事件。该配置项会被传给updateValueAndValidity方法。可选,默认值为{} |
options的具体参数为:
- onlySelf:如果为true,则每个变更仅仅影响当前控件,而不会影响父控件。默认为false。
- emitEvent:如果为true会未提供(默认),则当控件值发生变化时,statusChanges和valueChanges这两个Observable分别会以最近的状态和值发出事件。如果为false则不发出事件。
修补表单组中各个控件的值
const arr = new FormArray({
new FormControl(),
new FormControl()
});
console.log(arr.value); //[null,null]
arr.patchValue(['Nancy']);
console.log(form.value); //['Nancy',null]
3.3.8 reset()
重置这个FormArray,把它的各级子控件都标记为pristine和untouched,并把它们的值都设置为null。
也可以传入一个与表单结构相匹配的状态数组,来把表单重置为特定的状态。每个状态可以是一个单独的值,也可以是一个同时具有值和禁用状态的表单状态对象。
reset(value: any = {}, options: { onlySelf?: boolean; emitEvent?: boolean; } = {}): void
参数 | 数据类型 | 说明 |
---|---|---|
value | any | 各控件值的数组。可选,默认值是[] |
options | object | 当该组被重置时,此配置项会决定控件如何传播变更以及发出事件。该配置项会被传给updateValueAndValidity方法。可选,默认值为{} |
options的具体参数为:
- onlySelf:如果为true,则每个变更仅仅影响当前控件,而不会影响父控件。默认为false。
- emitEvent:如果为true会未提供(默认),则当控件值发生变化时,statusChanges和valueChanges这两个Observable分别会以最近的状态和值发出事件。如果为false则不发出事件。
重置该表单组的值
const arr = new FormArray({
new FormControl(),
new FormControl()
});
arr.reset(['name','last name']);
console.log(form.value); //['name','last name']
重置表单数组中的各个值和第一个控件的禁用状态
this.arr.reset([
{value: 'name', disabled: true},
'last'
]);
console.log(this.arr.value); // ['name', 'last name']
//代码示例来自官方文档,此处不清楚为何未重置成功,可能是两个表单状态格式要书写一致
console.log(this.arr.get('first'.status)); //'DISABLED'
3.3.9 getRawValue()
这个FormArray的聚合值,包括所有已禁用的控件。获取所有控件的值而不管其禁用状态。用value属性获取组中的值时,会从FormGroup中排除所有已禁用的控件。
getRawValue(): any[]
3.3.10 clear()
移除FormArray中所有的控件
gclear(): void
移除表单组中所有元素
const arr = new FormArray([
new FormControl(),
new FormControl()
]);
console.log(arr.length); // 2
arr.clear();
console.log(arr.length); // 0
相比一个一个删除元素,这是一种更简单更有效的替代方法
const arr = new FormArray([
new FormControl(),
new FormControl()
]);
while (arr.length) {
arr.removeAt(0);
}
3.4 具体示例
address.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 index=index">
<p>
Provience:<input [formControl]="address.get('provience')">
City:<input [formControl]="address.get('city')">
<button (click)="removeAddress(index)">Remove</button>
</p>
</div>
</div>
</div>
<button (click)="getInfo()">Get Info</button>
address.component.ts
import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-address',
templateUrl: './address.component.html',
styleUrls: ['./address.component.css']
})
export class AddressComponent{
address:FormArray;
info:FormGroup;
constructor(private fb:FormBuilder) {
this.createForm();
}
//初始化表单
createForm() {
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);
}
}
4 FormBuilder
使用用户指定的配置创建AbstractControl。它提供了一个语法糖,用来简化FormControl、FormGroup 或 FormArray 实例的创建过程。它会减少构建复杂表单时所需的样板代码的数量。
4.1 方法
4.1.1 group()
构建一个新的FormGroup实例。
group(controlsConfig: { [key: string]: any; }, options: AbstractControlOptions | { [key: string]: any; } = null): FormGroup
参数 | 数据类型 | 说明 |
---|---|---|
controlsConfig | object | 一组子控件。每个 key 就是注册进来的控件的名字。 |
options | AbstractControlOptions或{ [key: string]: any; } | FormGroup 的配置项对象。可选,默认值为null |
FormGroup 的配置项对象有两种形态。
(1) AbstractControlOptions对象(首选),它包括如下属性:
- validators:一个同步验证器函数或其数组
- asyncValidators:一个异步验证器函数或其数组
- updateOn:当发生哪个事件时该控件要被更新(选项)‘change’ | ‘blur’ | submit’
(2) 传统的配置对象,它包括如下属性:
- validator:一个同步验证器函数或其数组
- asyncValidator:一个异步验证器函数或其数组
4.1.2 control()
构建一个新的FormControl实例。
control(formState: any, validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[]): FormControl
参数 | 数据类型 | 说明 |
---|---|---|
formState | any | 使用一个初始值或定义了初始值和禁用状态的对象初始化该控件。可选,默认值为null |
validatorOrOpts | ValidatorFn或AbstractControlOptions或ValidatorFn[] | 一个同步验证器函数或其数组,或者一个包含验证函数和验证触发器的AbstractControlOptions对象。可选,默认值为undefined |
asyncValidator | AsyncValidatorFn或AsyncValidatorFn[] | 一个异步验证器函数或其数组。可选,默认值为undefined |
*把控件初始化为禁用状态
import {Component, Inject} from '@angular/core';
import {FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
/* . . . */
@Component({
selector: 'app-disabled-form-control',
template: `
<input [formControl]="control" placeholder="First">
`
})
export class DisabledFormControlComponent {
control: FormControl;
constructor(private fb: FormBuilder) {
this.control = fb.control({value: 'my val', disabled: true});
}
}
4.1.3 array()
构建一个新的FormArray实例。
control(formState: any, validatorOrOpts?: ValidatorFn | AbstractControlOptions | ValidatorFn[], asyncValidator?: AsyncValidatorFn | AsyncValidatorFn[]): FormControl
参数 | 数据类型 | 说明 |
---|---|---|
controlsConfig | any[] | 一个子控件数组。每个子控件的 key 都是它在数组中的索引 |
validatorOrOpts | ValidatorFn或AbstractControlOptions或ValidatorFn[] | 一个同步验证器函数或其数组,或者一个包含验证函数和验证触发器的AbstractControlOptions对象。可选,默认值为undefined |
asyncValidator | AsyncValidatorFn或AsyncValidatorFn[] | 一个异步验证器函数或其数组。可选,默认值为undefined |
4.2 具体示例
login.component.ts
import { checkNameValidator } from '../validators/name.validator';
import { PasswordValidator } from '../validators/password.validator';
import { FormBuilder, FormControl, FormGroup, Validator, Validators } from '@angular/forms';
import { Component } from '@angular/core';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginFormComponent {
info:FormGroup;
constructor(private fb:FormBuilder){
this.createForm();
}
createForm() {
this.info = this.fb.group({
name: ['jack', Validators.required, checkNameValidator()],
password: ['', [Validators.required, PasswordValidator()]]
});
}
onSubmit() {
console.log(this.info.value);
}
}
- 我们需要先在构造函数中注入FormBuilder,最好新建一个方法来初始化表单,这里我们在createForm方法中初始化表单。
- 借助FormBuilder我们可以通过参数来构建表单组,参数的结构与使用new基本一致,就不需要重复的写new FormGroup(…)、new FormControl(…)了。