명시적으로, 구성 요소 클래스에서 생성됨 | 암시적으로, 지침에 따라 생성 | | 데이터 모델 ...1.2 양식 모델 구축
반응형 양식과 템플릿 기반 양식 모두 사용자가 상호 작용하는 양식 입력 요소와 구성 요소 모델의 양식 데이터 간의 값 변경을 추적합니다. 두 방법 모두 동일한 기본 빌딩 블록
세트를 공유하지만 일반적으로 사용되는 양식 컨트롤 인스턴스
를 생성
및 관리
하는 방법만 다릅니다. > 차이가 있습니다. 构建块
,只在如何创建
和管理
常用表单控件实例
方面有所不同。
1.3 常用表单基础类
响应式表单和模板驱动表单都建立在下列基础类之上。
- FormControl 实例用于追踪单个表单控件的值和验证状态。
- FormGroup 用于追踪一个表单控件组的值和状态。
- FormArray 用于追踪表单控件数组的值和状态。
- ControlValueAccessor 用于在 Angular 的 FormControl 实例和原生 DOM 元素之间创建一个桥梁。
二、 响应式表单
响应式表单使用显式的、不可变的方式,管理表单在特定的时间点上的状态。对表单状态的每一次变更都会返回一个新的状态,这样可以在变化时维护模型的整体性。响应式表单是围绕 Observable
流构建的,表单的输入和值都是通过这些输入值组成的流来提供的,它可以同步
访问。
2.1 添加基础表单控件
使用表单控件有三个步骤。
要使用响应式表单控件,就要从 @angular/forms 包中导入 ReactiveFormsModule,并把它添加到你的 NgModule 的 imports 数组中。
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
// other imports ...
ReactiveFormsModule
],
})
export class AppModule { }
要注册一个表单控件,就要导入 FormControl 类并创建一个 FormControl 的新实例,将其保存为类的属性。
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 NameEditorComponent {
name = new FormControl('');
}
可以用 FormControl 的构造函数设置初始值
,这个例子中它是空字符串
。通过在你的组件类中创建这些控件,你可以直接对表单控件的状态进行监听
、修改
和校验
。
在组件类中创建了控件之后,你还要把它和模板中的一个表单控件关联起来。修改模板,为表单控件添加 formControl 绑定,formControl 是由 ReactiveFormsModule 中的 FormControlDirective 提供的。
<label>
Name:
<input type="text" [formControl]="name">
</label>
2.2 显示表单控件的值
你可以用下列方式显示它的值:
- 通过可观察对象
valueChanges
,你可以在模板中使用 AsyncPipe
或在组件类中使用 subscribe()
方法来监听表单值的变化。
- 使用 value 属性。它能让你获得当前值的一份快照。
<label>
Name:
<input type="text" [formControl]="name">
</label>
Value: {{ name.value }}
public name = new FormControl('test');
public testValueChange() {
this.name.valueChanges.subscribe({
next: value => {
console.log("name value is: " + value);
}
})
}
2.3 替换表单控件的值
响应式表单还有一些方法可以用编程的方式``修改
控件的值,它让你可以灵活的修改控件的值而不需要借助用户交互。FormControl 提供了一个 setValue()
方法,它会修改这个表单控件的值,并且验证与控件结构相对应的值的结构。比如,当从后端 API 或服务接收到了表单数据时,可以通过 setValue() 方法来把原来的值替换为新的值。
updateName() {
this.name.setValue('Nancy' + new Date().getTime());
}
<p>
<button (click)="updateName()">Update Name</button>
</p>
2.4 把表单控件分组
表单中通常会包含几个相互关联的控件
。响应式表单提供了两种把多个相关控件分组到同一个输入表单中的方法。
-
表单组
定义了一个带有一组控件的表单,你可以把它们放在一起管理。表单组的基础知识将在本节中讨论。你也可以通过嵌套表单组
来创建更复杂的表单。
-
表单数组
定义了一个动态表单,你可以在运行时添加和删除控件。你也可以通过嵌套表单数组
来创建更复杂的表单
要将表单组添加到此组件中,请执行以下步骤。
import { FormControl, FormGroup } from '@angular/forms';
profileForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
});
// 可以整个获取值
public onSubmit() {
// TODO: Use EventEmitter with form value
console.warn(this.profileForm.value);// {firstName: "", lastName: ""}
}
// 可以借助 valueChanges 整个可观察对象整个获取值
this.profileForm.valueChanges.subscribe( {
next: value => {
console.log("name value is: " + JSON.stringify(value)); // dashboard.component.ts:53 name value is: {"firstName":"dddd","lastName":"bb"}
}
})
// 可以通过后期单个控件单独获取值
this.profileForm.get('firstName').valueChanges.subscribe({
next: value => {
console.log("First Name is: " + value); // First Name is: aa
}
🎜🎜양식 컨트롤을 등록하려면 FormControl 클래스를 가져오고 FormControl의 새 인스턴스를 만들어 클래스 속성으로 저장하세요. 🎜<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<label>
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>
🎜FormControl의 생성자를 사용하여 초기 값을 설정
할 수 있습니다. 이 예에서는 빈 문자열
입니다. 구성 요소 클래스에 이러한 컨트롤을 생성하면 양식 컨트롤의 상태를 직접 모니터링
, 수정
및 확인
할 수 있습니다. 🎜🎜🎜구성 요소 클래스에서 컨트롤을 만든 후에는 이를 템플릿의 양식 컨트롤과 연결해야 합니다. 템플릿을 수정하고 양식 컨트롤에 formControl 바인딩을 추가합니다. formControl은 ReactiveFormsModule의 FormControlDirective에서 제공됩니다. 🎜 public profileForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
address: new FormGroup({
street: new FormControl(''),
city: new FormControl(''),
state: new FormControl(''),
zip: new FormControl('')
})
});
// 可以借助 valueChanges 整个可观察对象整个获取值
this.profileForm.valueChanges.subscribe( {
next: value => {
console.log("name value is: " + JSON.stringify(value));// name value is: {"firstName":"","lastName":"","address":{"street":"b","city":"","state":"","zip":""}}
}
});
// 可以通过后期单个控件单独获取值
this.profileForm.get('firstName').valueChanges.subscribe({
next: value => {
console.log("First Name is: " + value);
}
});
// 可以获取form组件某个form组的整个值
this.profileForm.get('address').valueChanges.subscribe(({
next: value => {
console.log('address value is: ' + JSON.stringify(value));// address value is: {"street":"b","city":"","state":"","zip":""}
}
}));
// 可以获取form组件某个form组的某个formcontrol实例的值
this.profileForm.get('address').get('street').valueChanges.subscribe(({
next: value => {
console.log('street value is: ' + value);// street value is: b
}
}));
🎜🎜2.2 양식 컨트롤의 값 표시 🎜🎜🎜다음과 같은 방법으로 해당 값을 표시할 수 있습니다. 🎜🎜관찰 가능한 valueChanges
를 사용하여 표시할 수 있습니다. 템플릿에서 AsyncPipe
를 사용하거나 구성 요소 클래스의 subscribe()
메서드를 사용하여 양식 값의 변경 사항을 수신합니다. 🎜🎜값 속성을 사용하세요. 이를 통해 현재 값의 스냅샷을 얻을 수 있습니다. 🎜🎜
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<label>
First Name:
<input type="text" formControlName="firstName">
</label>
<label>
Last Name:
<input type="text" formControlName="lastName">
</label>
<div formGroupName="address">
<h3>Address</h3>
<label>
Street:
<input type="text" formControlName="street">
</label>
<label>
City:
<input type="text" formControlName="city">
</label>
<label>
State:
<input type="text" formControlName="state">
</label>
<label>
Zip Code:
<input type="text" formControlName="zip">
</label>
</div>
<button type="submit" [disabled]="!profileForm.valid">Submit</button>
</form>
public updateProfile() {
// profileForm 模型中只有 firstName 和 street 被修改了。注意,street 是在 address 属性的对象中被修改的。这种结构是必须的,因为 patchValue() 方法要针对模型的结构进行更新。patchValue() 只会更新表单模型中所定义的那些属性。
this.profileForm.patchValue({
firstName: 'Nancy' + new Date().getTime(),
address: {
street: '123 Drew Street' + new Date().getTime()
}
});
// ERROR Error: Must supply a value for form control with name: 'lastName'.
// setValue() 方法会严格遵循表单组的结构
this.profileForm.setValue({
firstName: 'Nancy' + new Date().getTime(),
address: {
street: '123 Drew Street' + new Date().getTime()
}
});
}
🎜🎜2.3 양식 컨트롤 값 바꾸기 🎜🎜🎜반응형 양식에는 프로그래밍 방식으로 컨트롤 값을 ``수정하는 몇 가지 메서드가 있으므로 사용자 상호 작용이 필요합니다. FormControl은 이 양식 컨트롤의 값을 수정하고 컨트롤 구조에 해당하는 값의 구조를 확인하는 setValue()
메서드를 제공합니다. 예를 들어 백엔드 API나 서비스로부터 양식 데이터를 수신하면 setValue() 메서드를 통해 원래 값을 새 값으로 바꿀 수 있습니다. 🎜import { FormControl, FormGroup, FormArray } from '@angular/forms';
public profileForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
address: new FormGroup({
street: new FormControl(''),
city: new FormControl(''),
state: new FormControl(''),
zip: new FormControl('')
}),
aliases: new FormArray([
new FormControl('1')
])
});
public aliases = (<FormArray>this.profileForm.get('aliases'));
public addAlias() {
(<FormArray>this.profileForm.get('aliases')).push(new FormControl('1'));
}
// 获取整个 formArray 的数据
this.profileForm.get('aliases').valueChanges.subscribe({
next: value => {
console.log('aliases values is: ' + JSON.stringify(value)); // aliases values is: ["1","3"]
}
});
// 获取 formArray 中单个 formControl 的数据
(<FormArray>this.profileForm.get('aliases')).controls[0].valueChanges.subscribe({
next: value => {
console.log('aliases[0] values is: ' + value); // aliases[0] values is: 0
}
})
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<label>
First Name:
<input type="text" formControlName="firstName">
</label>
<label>
Last Name:
<input type="text" formControlName="lastName">
</label>
<div formGroupName="address">
<h3>Address</h3>
<label>
Street:
<input type="text" formControlName="street">
</label>
<label>
City:
<input type="text" formControlName="city">
</label>
<label>
State:
<input type="text" formControlName="state">
</label>
<label>
Zip Code:
<input type="text" formControlName="zip">
</label>
</div>
<div formArrayName="aliases">
<h3>Aliases</h3> <button (click)="addAlias()">Add Alias</button>
<div *ngFor="let alias of aliases.controls; let i=index">
<!-- The repeated alias template -->
<label>
Alias:
<input type="text" [formControlName]="i">
</label>
</div>
</div>
</form>
🎜🎜2.4 그룹 양식 컨트롤🎜🎜🎜양식에는 일반적으로 여러 상호 연관된 컨트롤
이 포함되어 있습니다. 반응형 양식은 여러 관련 컨트롤을 동일한 입력 양식으로 그룹화하는 두 가지 방법을 제공합니다. 🎜🎜양식 그룹
은 함께 관리할 수 있는 일련의 컨트롤이 포함된 양식을 정의합니다. 이 섹션에서는 양식 그룹의 기본 사항에 대해 설명합니다. 중첩된 양식 그룹
을 통해 더 복잡한 양식을 만들 수도 있습니다. 🎜🎜양식 배열
은 런타임에 컨트롤을 추가하고 제거할 수 있는 동적 양식을 정의합니다. 중첩된 양식 배열
을 사용하여 더 복잡한 양식을 만들 수도 있습니다.🎜🎜🎜이 구성 요소에 양식 그룹을 추가하려면 아래 단계를 따르세요. 🎜🎜🎜FormGroup
인스턴스를 생성합니다. 🎜🎜🎜🎜이 FormGroup 모델을 뷰에 연결합니다. 🎜🎜🎜🎜양식 데이터를 저장합니다. 🎜🎜🎜🎜🎜구성 요소 클래스에 profileForm이라는 속성을 생성하고 이를 FormGroup의 새 인스턴스로 설정합니다. 이 FormGroup을 초기화하려면 컨트롤로 구성된 개체를 생성자에 제공합니다. 개체의 각 이름은 양식 컨트롤의 이름과 일치해야 합니다. 🎜
import { FormControl, FormGroup } from '@angular/forms';
profileForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
});
// 可以整个获取值
public onSubmit() {
// TODO: Use EventEmitter with form value
console.warn(this.profileForm.value);// {firstName: "", lastName: ""}
}
// 可以借助 valueChanges 整个可观察对象整个获取值
this.profileForm.valueChanges.subscribe( {
next: value => {
console.log("name value is: " + JSON.stringify(value)); // dashboard.component.ts:53 name value is: {"firstName":"dddd","lastName":"bb"}
}
})
// 可以通过后期单个控件单独获取值
this.profileForm.get('firstName').valueChanges.subscribe({
next: value => {
console.log("First Name is: " + value); // First Name is: aa
}
ps: 这个 FormGroup 用对象的形式提供了它的模型值,这个值来自组中每个控件的值
。 FormGroup 实例拥有和 FormControl 实例相同的属性
(比如 value、untouched)和方法(比如 setValue())。
这个表单组还能跟踪其中每个控件的状态及其变化,所以如果其中的某个控件的状态或值变化了,父控件也会发出一次新的状态变更或值变更事件。该控件组的模型来自它的所有成员。在定义了这个模型之后,你必须更新模板,来把该模型反映到视图中。
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<label>
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>
2.5 创建嵌套的表单组
表单组可以同时接受单个表单控件实例和其它表单组实例作为其子控件。这可以让复杂的表单模型更容易维护,并在逻辑上把它们分组到一起。
要制作更复杂的表单,请遵循如下步骤。
要在 profileForm 中创建一个嵌套组,就要把一个嵌套的 address 元素添加到此表单组的实例中。
public profileForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
address: new FormGroup({
street: new FormControl(''),
city: new FormControl(''),
state: new FormControl(''),
zip: new FormControl('')
})
});
// 可以借助 valueChanges 整个可观察对象整个获取值
this.profileForm.valueChanges.subscribe( {
next: value => {
console.log("name value is: " + JSON.stringify(value));// name value is: {"firstName":"","lastName":"","address":{"street":"b","city":"","state":"","zip":""}}
}
});
// 可以通过后期单个控件单独获取值
this.profileForm.get('firstName').valueChanges.subscribe({
next: value => {
console.log("First Name is: " + value);
}
});
// 可以获取form组件某个form组的整个值
this.profileForm.get('address').valueChanges.subscribe(({
next: value => {
console.log('address value is: ' + JSON.stringify(value));// address value is: {"street":"b","city":"","state":"","zip":""}
}
}));
// 可以获取form组件某个form组的某个formcontrol实例的值
this.profileForm.get('address').get('street').valueChanges.subscribe(({
next: value => {
console.log('street value is: ' + value);// street value is: b
}
}));
在修改了组件类中的模型之后,还要修改模板,来把这个 FormGroup 实例对接到它的输入元素。
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<label>
First Name:
<input type="text" formControlName="firstName">
</label>
<label>
Last Name:
<input type="text" formControlName="lastName">
</label>
<div formGroupName="address">
<h3>Address</h3>
<label>
Street:
<input type="text" formControlName="street">
</label>
<label>
City:
<input type="text" formControlName="city">
</label>
<label>
State:
<input type="text" formControlName="state">
</label>
<label>
Zip Code:
<input type="text" formControlName="zip">
</label>
</div>
<button type="submit" [disabled]="!profileForm.valid">Submit</button>
</form>
2.6 更新部分数据模型
当修改包含多个 FormGroup 实例的值时,你可能只希望更新模型中的一部分,而不是完全替换掉。
有两种更新模型值的方式:
- 使用
setValue()
方法来为单个控件
设置新值。 setValue() 方法会严格遵循表单组的结构
,并整体性替换控件的值
。
- 使用
patchValue()
方法可以用对象中所定义的任何属性
为表单模型进行替换。
setValue() 方法的严格检查可以帮助你捕获复杂表单嵌套中的错误,而 patchValue() 在遇到那些错误时可能会默默的失败。
public updateProfile() {
// profileForm 模型中只有 firstName 和 street 被修改了。注意,street 是在 address 属性的对象中被修改的。这种结构是必须的,因为 patchValue() 方法要针对模型的结构进行更新。patchValue() 只会更新表单模型中所定义的那些属性。
this.profileForm.patchValue({
firstName: 'Nancy' + new Date().getTime(),
address: {
street: '123 Drew Street' + new Date().getTime()
}
});
// ERROR Error: Must supply a value for form control with name: 'lastName'.
// setValue() 方法会严格遵循表单组的结构
this.profileForm.setValue({
firstName: 'Nancy' + new Date().getTime(),
address: {
street: '123 Drew Street' + new Date().getTime()
}
});
}
2.7 创建动态表单
FormArray 是 FormGroup 之外的另一个选择,用于管理任意数量的匿名控件。像 FormGroup 实例一样,你也可以往 FormArray 中动态插入和移除控件,并且 FormArray 实例的值和验证状态也是根据它的子控件计算得来的。 不过,你不需要为每个控件定义一个名字作为 key,因此,如果你事先不知道子控件的数量,这就是一个很好的选择。
要定义一个动态表单,请执行以下步骤。
通过把一组(从零项到多项)控件定义在一个数组中来初始化一个 FormArray。为 profileForm 添加一个 aliases 属性,把它定义为 FormArray 类型。
import { FormControl, FormGroup, FormArray } from '@angular/forms';
public profileForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
address: new FormGroup({
street: new FormControl(''),
city: new FormControl(''),
state: new FormControl(''),
zip: new FormControl('')
}),
aliases: new FormArray([
new FormControl('1')
])
});
public aliases = (<FormArray>this.profileForm.get('aliases'));
public addAlias() {
(<FormArray>this.profileForm.get('aliases')).push(new FormControl('1'));
}
// 获取整个 formArray 的数据
this.profileForm.get('aliases').valueChanges.subscribe({
next: value => {
console.log('aliases values is: ' + JSON.stringify(value)); // aliases values is: ["1","3"]
}
});
// 获取 formArray 中单个 formControl 的数据
(<FormArray>this.profileForm.get('aliases')).controls[0].valueChanges.subscribe({
next: value => {
console.log('aliases[0] values is: ' + value); // aliases[0] values is: 0
}
})
要想为表单模型添加 aliases,你必须把它加入到模板中供用户输入。和 FormGroupNameDirective 提供的 formGroupName 一样,FormArrayNameDirective 也使用 formArrayName 在这个 FormArray 实例和模板之间建立绑定
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<label>
First Name:
<input type="text" formControlName="firstName">
</label>
<label>
Last Name:
<input type="text" formControlName="lastName">
</label>
<div formGroupName="address">
<h3>Address</h3>
<label>
Street:
<input type="text" formControlName="street">
</label>
<label>
City:
<input type="text" formControlName="city">
</label>
<label>
State:
<input type="text" formControlName="state">
</label>
<label>
Zip Code:
<input type="text" formControlName="zip">
</label>
</div>
<div formArrayName="aliases">
<h3>Aliases</h3> <button (click)="addAlias()">Add Alias</button>
<div *ngFor="let alias of aliases.controls; let i=index">
<!-- The repeated alias template -->
<label>
Alias:
<input type="text" [formControlName]="i">
</label>
</div>
</div>
</form>
2.8 响应式表单 API 汇总
类 |
说明 |
AbstractControl |
所有三种表单控件类(FormControl、FormGroup 和 FormArray)的抽象基类。它提供了一些公共的行为和属性。 |
FormControl |
管理单体表单控件的值和有效性状态。它对应于 HTML 的表单控件,比如 或 。 |
FormGroup |
管理一组 AbstractControl 实例的值和有效性状态。该组的属性中包括了它的子控件。组件中的顶层表单就是 FormGroup。 |
FormArray |
管理一些 AbstractControl 实例数组的值和有效性状态。 |
FormBuilder |
一个可注入的服务,提供一些用于提供创建控件实例的工厂方法。 |
三、模板驱动表单
在模板驱动表单中,表单模型是隐式的,而不是显式的。指令 NgModel 为指定的表单元素创建并管理一个 FormControl 实例。
下面的组件使用模板驱动表单为单个控件实现了同样的输入字段。
import { Component } from '@angular/core';
@Component({
selector: 'app-template-favorite-color',
template: `
Favorite Color: <input type="text" [(ngModel)]="favoriteColor">
`
})
export class FavoriteColorComponent {
favoriteColor = '';
}
四、响应式表单验证表单输入
在组件类中直接
把验证器函数添加到表单控件模型
上(FormControl)。然后,一旦控件发生了变化,Angular 就会调用这些函数。
4.1 验证器(Validator)函数
验证器函数可以是同步函数,也可以是异步函数。
- 同步验证器:这些同步函数接受一个控件实例,然后返回
一组验证错误或 null
。你可以在实例化一个 FormControl 时把它作为构造函数的第二个参数
传进去。
- 异步验证器 :这些异步函数接受一个控件实例并返回
一个 Promise 或 Observable
,它稍后
会发出一组验证错误或 null
。在实例化 FormControl 时,可以把它们作为第三个参数
传入。
出于性能方面的考虑,只有在所有同步验证器都通过之后,Angular 才会运行异步验证器。当每一个异步验证器都执行完之后,才会设置这些验证错误。
4.2 内置验证器函数
在模板驱动表单中用作属性的那些内置验证器,比如 required 和 minlength,也都可以作为 Validators 类中的函数使用
public profileForm = new FormGroup({
firstName: new FormControl('', [
Validators.required
]),
});
this.profileForm.get('firstName').valueChanges.subscribe({
next: value => {
console.log("First Name is: " + value);
console.log(this.profileForm.get('firstName').errors);// { required: true } | null
}
});
<form [formGroup]="profileForm">
<label>
First Name:
<input type="text" formControlName="firstName">
<div *ngIf="firstName.errors?.required">
Name is required.
</div>
</label>
</form>
4.3 定义自定义验证器
内置的验证器并不是总能精确匹配应用中的用例,因此有时你需要创建一个自定义验证器。
public profileForm = new FormGroup({
firstName: new FormControl('', [
Validators.required,
this.forbiddenNameValidator(/bob/i)
])
});
public forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} | null => {
const forbidden = nameRe.test(control.value);
return forbidden ? {forbiddenName: {value: control.value}} : null;
};
}
get firstName() { return this.profileForm.get('firstName'); }
this.profileForm.get('firstName').valueChanges.subscribe({
next: value => {
console.log("First Name is: " + value); // First Name is: bob
console.log(JSON.stringify(this.profileForm.get('firstName').errors));// {"forbiddenName":{"value":"bob"}} | null
}
});
4.4 跨字段交叉验证
跨字段交叉验证器是一种自定义验证器
,可以对表单中不同字段的值进行比较,并针对它们的组合进行接受或拒绝。
下列交叉验证的例子说明了如何进行如下操作:
- 根据两个兄弟控件的值验证响应式表单或模板驱动表单的输入,
- 当用户与表单交互过,且验证失败后,就会显示描述性的错误信息
要想在单个自定义验证器中计算这两个控件,你就必须在它们共同的祖先控件中执行验证: FormGroup。你可以在 FormGroup 中查询它的子控件,从而让你能比较它们的值。要想给 FormGroup 添加验证器,就要在创建时把一个新的验证器传给它的第二个参数。
this.profileForm.valueChanges.subscribe( {
next: value => {
console.log(JSON.stringify(this.profileForm.errors));// {"identityRevealed":true} | null
}
});
public profileForm = new FormGroup({
firstName: new FormControl('', [
Validators.required,
]),
lastName: new FormControl(''),
}, { validators: this.identityRevealedValidator});
public identityRevealedValidator(control: FormGroup): ValidationErrors | null{
const firstName = control.get('firstName');
const lastName = control.get('lastName');
return firstName && lastName && firstName.value === lastName.value ? { identityRevealed: true } : null;
};
4.5 创建异步验证器
异步验证器实现了 AsyncValidatorFn
和 AsyncValidator
接口。它们与其同步版本非常相似,但有以下不同之处。
- validate() 函数必须返回一个
Promise 或可观察对象
,
- 返回的可观察对象必须是
有尽
的,这意味着它必须在某个时刻完成(complete)
。要把无尽的可观察对象转换成有尽的,可以在管道中加入过滤操作符,比如 first、last、take 或 takeUntil。
异步验证在同步验证完成后才会发生
,并且只有在同步验证成功时才会执行。如果更基本的验证方法已经发现了无效输入,那么这种检查顺序就可以让表单避免使用昂贵的异步验证流程(例如 HTTP 请求)。
4.6 触发某个formControlName
let formControl = this.profileForm.get('firstName');
formControl.updateValueAndValidity();
更多编程相关知识,请访问:编程视频!!