1. 程式人生 > >Angular 從入坑到挖坑 - 表單控制元件概覽

Angular 從入坑到挖坑 - 表單控制元件概覽

### 一、Overview angular 入坑記錄的筆記第三篇,介紹 angular 中表單控制元件的相關概念,瞭解如何在 angular 中建立一個表單,以及如何針對表單控制元件進行資料校驗。 對應官方文件地址: - [Angular 表單簡介](https://angular.cn/guide/forms-overview) - [響應式表單](https://angular.cn/guide/reactive-forms) - [模板驅動表單](https://angular.cn/guide/forms) - [表單驗證](https://angular.cn/guide/form-validation) 配套程式碼地址:[angular-practice/src/forms-overview](https://github.com/Lanesra712/angular-practice/tree/master/src/forms-overview "angular forms overview") ### 二、Contents 1. [Angular 從入坑到棄坑 - Angular 使用入門](https://www.cnblogs.com/danvic712/p/getting-started-with-angular.html) 2. [Angular 從入坑到挖坑 - 元件食用指南](https://www.cnblogs.com/danvic712/p/angular-components-guide.html) 3. [Angular 從入坑到挖坑 - 表單控制元件概覽](https://www.cnblogs.com/danvic712/p/angular-forms-overview.html) ### 三、Knowledge Graph ![思維導圖](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304210835288-1168947076.png) ### 四、Step by Step #### 4.1、表單簡介 用來處理使用者的輸入,通過從檢視中捕獲使用者的輸入事件、驗證使用者輸入的是否滿足條件,從而創建出表單模型修改元件中的資料模型,達到獲取使用者輸入資料的功能 | | 模板驅動表單 | 響應式表單 | | -------- | ---------------------------- | -------------------------------- | | 建立表單 | 由元件隱式的建立表單控制元件例項 | 在元件類中進行顯示的建立控制元件例項 | | 表單驗證 | 指令 | 函式 | 在表單資料發生變更時,模板驅動表單通過修改 ngModel 繫結的資料模型來完成資料更新,而響應式表單在表單資料發生變更時,FormControl 例項會返回一個新的資料模型,而不是直接修改原來的資料模型 #### 4.2、模板驅動表單 通過使用表單的專屬指令(例如 ngModel 進行雙向資料繫結)將資料值和一些對於使用者的行為約束(某個欄位必須填啊、某個欄位長度超過了長度限制啊)繫結到元件的模板中,從而完成與使用者的互動 ##### 4.2.1、模板驅動表單的雙向資料繫結 在根模組中引入 FormsModule,並新增到根模組的 imports 陣列中 ```typescript import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; // 引入 FormsModule import { FormsModule } from '@angular/forms'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { TemplateDrivenFormsComponent } from './template-driven-forms/template-driven-forms.component'; @NgModule({ declarations: [ AppComponent, ReactiveFormsComponent, DynamicFormsComponent, TemplateDrivenFormsComponent ], imports: [ BrowserModule, AppRoutingModule, FormsModule // 新增到應用模組中 ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } ``` 新建一個類檔案,用來承載元件與模板之間進行雙向資料繫結的資料資訊 ```bash ng g class classes/hero ``` ```typescript export class Hero { /** * ctor * @param name 姓名 * @param age 年紀 * @param gender 性別 * @param location 住址 */ constructor(public name: string, public age: number, public gender: string, public location: string) { } } ``` 在元件的模板中建立承載資料的表單資訊,並使用 ngModel 完成元件與模板之間的資料雙向繫結 ```html

表單的資料資訊:{{hero | json}}

``` ```typescript import { Component, OnInit } from '@angular/core'; import { Hero } from './../classes/hero'; @Component({ selector: 'app-template-driven-forms', templateUrl: './template-driven-forms.component.html', styleUrls: ['./template-driven-forms.component.scss'] }) export class TemplateDrivenFormsComponent implements OnInit { constructor() { } // 性別選項 public genders = [{ id: 'male', text: '男', value: true }, { id: 'female', text: '女', value: false }]; /** * 住址下拉 */ public locations: Array = ['beijing', 'shanghai', 'hangzhou', 'wuhan']; hero = new Hero('', 18, 'true', 'beijing'); ngOnInit(): void { } submit() { } } ``` ![雙向繫結](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304210905000-2115592353.gif) 在使用 ngModel 進行模板繫結時,angular 在 form 標籤上自動附加了一個 NgForm 指令,因為 NgForm 指令會控制表單中帶有 ngModel 指令和 name 屬性的元素,而 name 屬性則是 angular 用來註冊控制元件的 key,所以在表單中使用 ngModel 進行雙向資料繫結時,必須要新增 name 屬性 ##### 4.2.2、跟蹤表單控制元件的狀態 在表單中使用 ngModel 之後,NgModel 指令通過更新控制元件的 css 類,達到反映控制元件狀態的目的 | 狀態 | 發生時的 css 類 | 沒發生的 css 類 | | ---------------- | --------------- | --------------- | | 控制元件被訪問 | ng-touched | ng-untouched | | 控制元件的值發生變化 | ng-dirty | ng-pristine | | 控制元件的值是否有效 | ng-valid | ng-invalid | ![跟蹤表單控制元件的狀態](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304210949400-640727338.gif) 通過這些控制元件的 css 類樣式,就可以通過新增自定義的 css 樣式在使用者輸入內容不滿足條件時進行提示 ```css .ng-valid[required], .ng-valid.required { border-left: 5px solid #42A948; /* green */ } .ng-invalid:not(form) { border-left: 5px solid #a94442; /* red */ } ``` ![給予使用者輸入驗證的視覺反饋](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211006180-623107229.png) ##### 4.2.3、資料的有效性驗證 某些時候需要對於使用者輸入的資訊做有效性驗證,此時可以在控制元件上新增上[原生的 HTML 表單驗證器](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation)來設定驗證條件,當表單控制元件的資料發生變化時,angular 會通過指令的方式對資料進行驗證,從而生成錯誤資訊列表 在進行使用者輸入資料有效性驗證時,在控制元件上通過新增一個模板引用變數來暴露出 ngModel,從而在模板中獲取到指定控制元件的狀態資訊,之後就可以通過獲取錯誤資訊列表來進行反饋 ```html
姓名不能為空 姓名資訊不能少於 4 個字元長度 ``` ![資料驗證](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211020756-1506857714.gif) 在資料驗證失敗的情況下,對於系統來說,表單是不允許提交的,因此可以將提交事件繫結到表單的 ngSubmit 事件屬性上,通過模板引用變數的形式,在提交按鈕處進行資料有效性判斷,當無效時,禁用表單的提交按鈕 ```html
姓名不能為空 姓名資訊不能少於 4 個字元長度 ``` ![繫結 ngSubmit 事件](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211039228-1118442844.gif) #### 4.3、響應式表單 ##### 4.3.1、快速上手 響應式表單依賴於 ReactiveFormsModule 模組,因此在使用前需要在根模組中引入 ```typescript import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; // 引入 ReactiveFormsModule import { ReactiveFormsModule } from '@angular/forms'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { ReactiveFormsComponent } from './reactive-forms/reactive-forms.component'; @NgModule({ declarations: [ AppComponent, ReactiveFormsComponent, DynamicFormsComponent, TemplateDrivenFormsComponent ], imports: [ BrowserModule, AppRoutingModule, ReactiveFormsModule // 新增到應用模組中 ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } ``` 在使用響應式表單時,一個 FormControl 類的例項對應於一個表單控制元件,在使用時,通過將控制元件的例項賦值給屬性,後續則可以通過監聽這個自定義的屬性來跟蹤表單控制元件的值和狀態 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormControl 物件 import { FormControl } from '@angular/forms'; @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { // 定義屬性用來承接 FormControl 例項 public name = new FormControl(''); constructor() { } ngOnInit(): void { } } ``` 當在元件中建立好控制元件例項後,通過給檢視模板上的表單控制元件新增 formControl 屬性繫結,從而將控制元件例項與模板中的表單控制元件關聯起來 ```html name 控制元件的資料值: {{ name | json }} ``` ![繫結表單屬性與表單控制元件](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211056639-1211221943.gif) 通過使用 FormControl 控制元件的 value 屬性,可以獲得當前表單控制元件的一份資料值拷貝,通過 setValue 方法則可以更新表單的控制元件值 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormControl 物件 import { FormControl } from '@angular/forms'; @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { // 定義屬性用來承接 FormControl 例項 public name = new FormControl('12345'); constructor() { } ngOnInit(): void { } getName() { alert(this.name.value); } setName() { this.name.setValue(1111111); } } ``` ![控制元件的資料操作](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211112928-519962299.gif) ##### 4.3.2、通過 FomGroup 組合多個控制元件 一個表單不可能只有一個控制元件,通過在元件中構造 FormGroup 例項來完成對於多個表單控制元件的統一管理 在使用 FormGroup 時,同樣在元件中定義一個屬性用來承載控制元件組例項,然後將控制元件組中的每一個控制元件作為屬性值新增到例項中 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormControl 和 FormGroup 物件 import { FormControl, FormGroup } from '@angular/forms'; @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { // 定義物件屬性來承接 FormGroup 例項 public profileForm = new FormGroup({ name: new FormControl('啦啦啦'), age: new FormControl(12) }); constructor() { } ngOnInit(): void { } } ``` 在檢視模板中,將承接 FormGroup 例項的屬性通過 formGroup 指令繫結到 form 元素,然後將控制元件組的每一個屬性通過 formControlName 繫結到具體對應的表單控制元件上 ```html FormGroup 表單組控制元件的值: {{ profileForm.value | json }} ``` ![通過 FormGroup 管理多個控制元件](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211133448-820561210.gif) 當構建複雜表單時,可以在 FormGroup 中通過巢狀 FormGroup 使表單的結構更合理 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormControl 和 FormGroup 物件 import { FormControl, FormGroup } from '@angular/forms'; @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { // 定義物件屬性來承接 FormGroup 例項 public profileForm = new FormGroup({ name: new FormControl('啦啦啦'), age: new FormControl(12), address: new FormGroup({ province: new FormControl('北京市'), city: new FormControl('北京'), district: new FormControl('朝陽區'), street: new FormControl('三里屯街道') }) }); constructor() { } ngOnInit(): void { } submit() { alert(JSON.stringify(this.profileForm.value)); } } ``` 在檢視模板中,通過使用 formGroupName 屬性將 FormGroup 控制元件組中的 FormGroup 例項繫結到控制元件上 ```html FormGroup 表單組控制元件的值: {{ profileForm.value | json }} ``` ![FormGroup 巢狀](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211154840-2014161687.gif) 對於使用了 FormGroup 的表單來說,當使用 setValue 進行資料更新時,必須保證新的資料結構與原來的結構相同,否則就會報錯 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormControl 和 FormGroup 物件 import { FormControl, FormGroup } from '@angular/forms'; @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { // 定義物件屬性來承接 FormGroup 例項 public profileForm = new FormGroup({ name: new FormControl('啦啦啦'), age: new FormControl(12), address: new FormGroup({ province: new FormControl('北京市'), city: new FormControl('北京'), district: new FormControl('朝陽區'), street: new FormControl('三里屯街道') }) }); constructor() { } ngOnInit(): void { } submit() { alert(JSON.stringify(this.profileForm.value)); } updateProfile() { this.profileForm.setValue({ name: '423' }); } } ``` ![FormGroup 使用 setValue 更新資料](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211208160-1174512460.png) 某些情況下,我們只是想要更新控制元件組中的某個控制元件的資料值,這時需要使用 patchValue 的方式進行更新 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormControl 和 FormGroup 物件 import { FormControl, FormGroup } from '@angular/forms'; @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { // 定義物件屬性來承接 FormGroup 例項 public profileForm = new FormGroup({ name: new FormControl('啦啦啦'), age: new FormControl(12), address: new FormGroup({ province: new FormControl('北京市'), city: new FormControl('北京'), district: new FormControl('朝陽區'), street: new FormControl('三里屯街道') }) }); constructor() { } ngOnInit(): void { } submit() { alert(JSON.stringify(this.profileForm.value)); } updateProfile() { this.profileForm.patchValue({ name: '12345' }); } } ``` ![使用 patchValue 更新控制元件資料](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211226016-44544425.gif) ##### 4.3.3、使用 FormBuilder 生成表單控制元件 當控制元件過多時,通過 FormGroup or FormControl 手動的構建表單控制元件的方式會很麻煩,因此這裡可以通過依賴注入 FormBuilder 類的方式來簡化的完成表單的構建 FormBuilder 服務有三個方法:control、group 和 array,用於在元件類中分別生成 FormControl、FormGroup 和 FormArray 使用 FormBuilder 構建的控制元件,每個控制元件名對應的值都是一個數組,第一個值為控制元件的預設值,第二項和第三項則是針對這個值設定的同步、非同步驗證方法 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormBuilder 構建表單控制元件 import { FormBuilder } from '@angular/forms'; @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { /** * ctor * @param formBuilder 表單構造器 */ constructor(private formBuilder: FormBuilder) { } public profileForm = this.formBuilder.group({ name: ['啦啦啦'], age: [12], address: this.formBuilder.group({ province: ['北京市'], city: ['北京'], district: ['朝陽區'], street: ['三里屯街道'] }) }); ngOnInit(): void { } } ``` ##### 4.3.4、資料的有效性驗證 同模板驅動表單的資料有效性驗證相同,在響應式表單中同樣可以使用原生的表單驗證器,在設定規則時,需要將模板中控制元件名對應的資料值的第二個引數改為驗證的規則 在響應式表單中,資料來源來源於元件類,因此應該在元件類中直接把驗證器函式新增到對應的 FormControl 的建構函式上。然後,一旦控制元件資料發生了變化,angular 就會呼叫這些函式 這裡建立針對指定控制元件的 getter 方法,從而在模板中通過此方法來獲取到指定控制元件的狀態資訊 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormBuilder 構建表單控制元件 import { FormBuilder } from '@angular/forms'; // 引入 Validators 驗證器 import { Validators } from '@angular/forms'; @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { /** * ctor * @param formBuilder 表單構造器 */ constructor(private formBuilder: FormBuilder) { } public profileForm = this.formBuilder.group({ name: ['', [ Validators.required, Validators.minLength(4) ]], age: [12], address: this.formBuilder.group({ province: ['北京市'], city: ['北京'], district: ['朝陽區'], street: ['三里屯街道'] }) }); // 新增需要驗證控制元件 getter 方法,用來在模板中獲取狀態值 get name() { return this.profileForm.get('name'); } ngOnInit(): void { } } ``` ```html 姓名不能為空 姓名資訊不能少於 4 個字元長度   FormGroup 表單組控制元件的值: {{ profileForm.value | json }} ``` ![資料的有效性驗證](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211252608-2058131021.gif) #### 4.4、表單的自定義資料驗證 ##### 4.4.1、自定義驗證器 在很多的情況下,原生的驗證規則無法滿足我們的需要,此時需要建立自定義的驗證器來實現 對於響應式表單,我們可以定義一個方法,對控制元件的資料進行校驗,之後將方法作為引數新增到控制元件定義處即可 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormBuilder 構建表單控制元件 import { FormBuilder } from '@angular/forms'; // 引入 Validators 驗證器 import { Validators } from '@angular/forms'; /** * 自定義驗證方法 * @param name 控制元件資訊 */ function validatorName(name: FormControl) { return name.value === 'lala' ? { nameinvalid: true } : null; } @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { /** * ctor * @param formBuilder 表單構造器 */ constructor(private formBuilder: FormBuilder) { } public profileForm = this.formBuilder.group({ name: ['', [ Validators.required, Validators.minLength(4), validatorName // 新增自定義驗證方法 ]], age: [12], address: this.formBuilder.group({ province: ['北京市'], city: ['北京'], district: ['朝陽區'], street: ['三里屯街道'] }) }); // 新增需要驗證控制元件 getter 方法,用來在模板中獲取狀態值 get name() { return this.profileForm.get('name'); } ngOnInit(): void { } } ``` 在驗證方法中,當資料有效時,返回 null,當資料無效時,則會返回一個物件資訊,這裡的 nameinvalid 就是我們在模板中獲取到的錯誤資訊的 key 值 ```html 姓名不能為空 姓名資訊不能少於 4 個字元長度 姓名無效 ``` ![響應式表單控制元件的自定義資料驗證](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211312580-305727842.gif) 在模板驅動表單中,因為不是直接使用的 FormControl 例項,因此這裡應該在模板上新增一個自定義的指令來完成對於控制元件資料的校驗 使用 angular cli 建立一個用來進行表單驗證的指令 ```bash ng g directive direactives/hero-validate ``` 在建立完成指令之後,我們需要將這個指令將該驗證器新增到已經存在的驗證器集合中,同時為了使這個指令可以與 angular 表單整合在一起,我們需要繼承 Validator 介面 ```typescript import { Directive, Input } from '@angular/core'; import { AbstractControl, Validator, ValidationErrors, NG_VALIDATORS } from '@angular/forms'; @Directive({ selector: '[appHeroValidate]', // 將指令註冊到 NG_VALIDATORS 使用 multi: true 將該驗證器新增到現存的驗證器集合中 providers: [{ provide: NG_VALIDATORS, useExisting: HeroValidateDirective, multi: true }] }) export class HeroValidateDirective implements Validator { constructor() { } /** * 對指定的控制元件執行同步驗證方法 * @param control 控制元件 */ validate(control: AbstractControl): ValidationErrors | null { return control.value === 'lala' ? { 'nameInvalid': true } : null; } } ``` 當實現了繼承的 validate 方法後,就可以在模板的控制元件上新增該指令 ```html 姓名不能為空 姓名資訊不能少於 4 個字元長度 姓名無效 ``` ![模板驅動表單的資料驗證](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211329420-41787785.gif) ##### 4.4.2、跨欄位的交叉驗證 有時候需要針對表單中的多個控制元件資料進行交叉驗證,此時就需要針對整個 FormGroup 進行驗證。因此這裡的驗證方法需要在定義控制元件組時作為 FormGroup 的引數傳入 與單個欄位的驗證方式相似,通過實現 ValidatorFn 介面,當表單資料有效時,它返回一個 null,否則返回 ValidationErrors 物件 ```typescript import { Component, OnInit } from '@angular/core'; // 引入 FormControl 和 FormGroup 物件 import { FormControl, FormGroup, ValidatorFn, ValidationErrors } from '@angular/forms'; // 引入 FormBuilder 構建表單控制元件 import { FormBuilder } from '@angular/forms'; // 引入 Validators 驗證器 import { Validators } from '@angular/forms'; /** * 跨欄位驗證 * @param controlGroup 控制元件組 */ const nameAgeCrossValidator: ValidatorFn = (controlGroup: FormGroup): ValidationErrors | null => { // 獲取子控制元件的資訊 // const name = controlGroup.get('name'); const age = controlGroup.get('age'); return name && age && name.value === 'lala' && age.value === 12 ? { 'nameAgeInvalid': true } : null; }; @Component({ selector: 'app-reactive-forms', templateUrl: './reactive-forms.component.html', styleUrls: ['./reactive-forms.component.scss'] }) export class ReactiveFormsComponent implements OnInit { /** * ctor * @param formBuilder 表單構造器 */ constructor(private formBuilder: FormBuilder) { } public profileForm = this.formBuilder.group({ name: ['', [ Validators.required, Validators.minLength(4), validatorName ]], age: [12], address: this.formBuilder.group({ province: ['北京市'], city: ['北京'], district: ['朝陽區'], street: ['三里屯街道'] }) }, { validators: [nameAgeCrossValidator] }); // 新增針對控制元件組的驗證器 ngOnInit(): void { } } ``` 在針對多個欄位進行交叉驗證時,在模板頁面中,則需要通過獲取整個表單的錯誤物件資訊來獲取到交叉驗證的錯誤資訊 ```html 姓名不能為空 姓名資訊不能少於 4 個字元長度 姓名無效 lala 不能是 12 歲 ``` ![響應式表單的跨欄位交叉驗證](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211346828-877955238.gif) 對於模板驅動表單,同樣是採用自定義指令的方式進行跨欄位的交叉驗證,與單個控制元件的驗證不同,此時需要將指令新增到 form 標籤上,然後使用模板引用變數來獲取錯誤資訊 ```typescript import { Directive } from '@angular/core'; import { Validator, AbstractControl, ValidationErrors, ValidatorFn, FormGroup, NG_VALIDATORS } from '@angular/forms'; /** * 跨欄位驗證 * @param controlGroup 控制元件組 */ const nameAgeCrossValidator: ValidatorFn = (controlGroup: FormGroup): ValidationErrors | null => { // 獲取子控制元件的資訊 // const name = controlGroup.get('name'); const age = controlGroup.get('age'); return name && age && name.value === 'lala' && age.value === 12 ? { 'nameAgeInvalid': true } : null; }; @Directive({ selector: '[appCrossFieldValidate]', providers: [{ provide: NG_VALIDATORS, useExisting: CrossFieldValidateDirective, multi: true }] }) export class CrossFieldValidateDirective implements Validator { constructor() { } validate(control: AbstractControl): ValidationErrors | null { return nameAgeCrossValidator(control); } } ``` ![模板驅動表單的跨欄位交叉驗證](https://img2020.cnblogs.com/blog/1310859/202003/1310859-20200304211400080-661641