如何在Angular中使用自定义表单验证
介绍
验证器用于确保表单中的值满足某些要求。 它们可用于 Angular 应用程序中的 模板驱动表单 或 反应式表单。
有几个内置的验证器,例如 required
、email
、pattern
和 minLength
。 还可以开发自定义验证器来解决内置验证器无法处理的功能。
例如,电话号码验证器将包含一个输入字段,除非该值长为十位,否则不会被视为有效。
这是一个电话号码输入字段的屏幕截图,该字段提供了一个九位数的无效号码:
这是一个电话号码输入字段的屏幕截图,该字段提供了一个十位数长的有效号码:
在本教程中,您将为 Angular 应用程序中的电话号码输入字段构建一个自定义验证器。
先决条件
要完成本教程,您需要:
- Node.js 安装在本地,您可以按照【X57X】如何安装Node.js 并创建本地开发环境【X126X】进行。
- 熟悉 设置 Angular 项目 。
本教程已使用 Node v15.2.1、npm
v6.14.8、@angular/core
v11.0.0 和 @angular/forms
v11.0.0 进行了验证。
设置项目
就本教程而言,您将从使用 @angular/cli
生成的默认 Angular 项目构建。
npx @angular/cli new angular-custom-validation-example --style=css --routing=false --skip-tests
注意:或者,您可以全局安装 @angular/cli
。
这将配置一个新的 Angular 项目,其样式设置为“CSS”(与“Sass”、“Less”或“Stylus”相对)、无路由和跳过测试。
导航到新创建的项目目录:
cd angular-custom-validation-example
此时,您将拥有一个新的 Angular 项目。
在模板驱动的表单中使用验证器
Directives 用于在模板驱动的表单中进行验证。 对于此示例,您将使用 @angular/cli
创建一个 phone-number-validator
指令。
首先,打开终端并使用作为开发依赖项安装的 @angular/cli
包生成新指令:
./node_modules/@angular/cli/bin/ng generate directive phone-number-validator
这将创建 phone-number-validator.directive.ts
和 phone-number-validator.directive.spec.ts
。 它还将 PhoneNumberValidatorDirective
添加到 app.module.ts
。
接下来,在代码编辑器中打开 phone-number-validator.directive.ts
。 添加 Validator
、AbstractControl
和 NG_VALIDATORS
:
src/app/phone-number-validator.directive.ts
import { Directive } from '@angular/core'; import { AbstractControl, Validator, NG_VALIDATORS } from '@angular/forms'; @Directive({ selector: '[appPhoneNumberValidator]', providers: [{ provide: NG_VALIDATORS, useExisting: PhoneNumberValidatorDirective, multi: true }] }) export class PhoneNumberValidatorDirective implements Validator { validate(control: AbstractControl) : {[key: string]: any} | null { if (control.value && control.value.length != 10) { return { 'phoneNumberInvalid': true }; } return null; } }
这段代码创建了一个实现 @angular/forms
的 Validator
的指令。 它将需要以下实现方法:validate(control: AbstractControl): : {[key: string]: any} | null
。 此验证器将返回一个对象 - { 'phoneNumberInvalid': true }
- 如果值不等于长度不等于十个字符的条件。 否则,如果值满足条件,则返回null
。
接下来,打开终端并使用作为开发依赖项安装的 @angular/cli
包生成新指令:
./node_modules/@angular/cli/bin/ng generate component template-driven-form-example --flat
此命令将创建 template-driven-form-example.component.ts
和 template-driven-form-example.component.html
文件。 它还将 TemplateDrivenFormExampleComponent
添加到 app.module.ts
。
接下来,在代码编辑器中打开 template-driven-form-example.component.ts
并添加初始值为空字符串的 phone
:
src/app/template-driven-form-example.component.ts
import { Component } from '@angular/core'; @Component({ selector: 'app-template-driven-form-example', templateUrl: './template-driven-form-example.component.html', styleUrls: ['./template-driven-form-example.component.css'] }) export class TemplateDrivenFormExampleComponent { phone = ''; }
Angular 在 FormControl / NgModel 的 errors
属性中添加验证函数的返回值。 如果 FormControl
/ NgModel
的 errors
属性不为空,则表单无效。 如果 errors
属性为空,则表单有效。
要在模板驱动的表单中使用该指令,请打开 template-driven-form-example.component.html
并添加以下代码:
src/app/template-driven-form-example.component.html
<div class="form-group"> <label>Phone <input type="text" class="form-control" name="phone" [(ngModel)]="phone" #phoneNgModel="ngModel" appPhoneNumberValidator [class.is-invalid]="(phoneNgModel.touched || phoneNgModel.dirty) && phoneNgModel.errors?.phoneNumberInvalid" > </label> <span class="invalid-feedback" *ngIf="(phoneNgModel.touched || phoneNgModel.dirty) && phoneNgModel.errors?.phoneNumberInvalid" > Phone number must be 10 digits </span> </div>
此代码创建一个 <input>
元素和 <span>
并带有错误消息。 <input>
元素使用指令的 ngModel
和 appPhoneNumberValidator
选择器。
如果 <input>
已经是 touched
或 dirty
并且验证不通过,则会发生两种情况。 首先,类 is-invalid
将应用于 <input>
。 其次,将显示带有错误消息的<span>
。
注意: 这里的一些类 - form-group
、form-control
、invalid-feedback
和 is-valid
- 是 Bootstrap 框架的一部分。 这些不是完成本教程所必需的,但可以为表单提供视觉美感。
然后,在代码编辑器中打开 app.module.ts
并添加 FormModule
:
src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { PhoneNumberValidatorDirective } from './phone-number-validator.directive'; import { TemplateDrivenFormExampleComponent } from './template-driven-form-example.component'; @NgModule({ declarations: [ AppComponent PhoneNumberValidatorDirective, TemplateDrivenFormExampleComponent ], imports: [ BrowserModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
最后,打开 app.component.html
并将内容替换为您的 TemplateDrivenFormExample
:
src/app/app.component.html
<app-template-driven-form-example></app-template-driven-form-example>
您可以运行 npm start
命令并在 Web 浏览器中与您的输入进行交互。 如果您在电话字段中输入少于或多于 10 个字符,则会显示错误消息。
此时,您有一个使用模板驱动表单中的指令的自定义验证器。
在响应式表单中使用验证器
响应式表单不是使用指令,而是使用函数进行验证。
首先,打开终端并使用作为开发依赖项安装的 @angular/cli
包生成新指令:
./node_modules/@angular/cli/bin/ng generate component reactive-form-example --flat
此命令将创建 reactive-form-example.component.ts
和 reactive-form-example.component.html
文件。 它还将 ReactiveFormExampleComponent
添加到 app.module.ts
。
接下来,在代码编辑器中打开 reactive-form-example.component.ts
并添加 FormBuilder
和 AbstractControl
:
src/app/reactive-form-example.component.ts
import { Component, OnInit } from "@angular/core"; import { AbstractControl, FormBuilder, FormGroup } from '@angular/forms'; @Component({ selector: 'app-reactive-form-example', templateUrl: './reactive-form-example.component.html', styleUrls: ['./reactive-form-example.component.css'] }) export class ReactiveFormExampleComponent implements OnInit { myForm: FormGroup; constructor(private fb: FormBuilder) {} ngOnInit(): void { this.myForm = this.fb.group({ phone: ['', [ValidatePhone]] }); } saveForm(form: FormGroup) { console.log('Valid?', form.valid); // true or false console.log('Phone Number', form.value.phone); } } function ValidatePhone(control: AbstractControl): {[key: string]: any} | null { if (control.value && control.value.length != 10) { return { 'phoneNumberInvalid': true }; } return null; }
此代码创建一个 ValidatePhone
函数并将其添加到 FormControl
的验证器数组中。
在代码编辑器中打开 reactive-form-example.component.html
并创建以下表单:
src/app/reactive-form-example.component.html
<form class="needs-validation" novalidate [formGroup]="myForm" (ngSubmit)="saveForm(myForm)" > <div class="row"> <div class="form-group col-sm-4"> <label> Phone <input type="text" class="form-control" formControlName="phone" [class.is-invalid]="(myForm.get('phone').touched || myForm.get('phone').dirty) && myForm.get('phone').invalid" > </label> <span class="invalid-feedback" *ngIf="(myForm.get('phone').touched || myForm.get('phone').dirty) && myForm.get('phone').invalid" > Phone number must be 10 digits </span> </div> </div> </form>
与模板驱动的表单不同,此表单具有 form
并使用 [formGroup]
、(ngSubmit)
、formControlName
和 get
。
然后,在代码编辑器中打开 app.module.ts
并添加 ReactiveFormsModule
:
src/app/app.module.ts
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { PhoneNumberValidatorDirective } from './phone-number-validator.directive'; import { ReactiveFormExampleComponent } from './reactive-form-example.component'; import { TemplateDrivenFormExampleComponent } from './template-driven-form-example.component'; @NgModule({ declarations: [ AppComponent, PhoneNumberValidatorDirective, ReactiveFormExampleComponent, TemplateDrivenFormExampleComponent ], imports: [ BrowserModule, FormsModule, ReactiveFormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
最后,打开 app.component.html
并将内容替换为您的 ReactiveFormExample
:
src/app/app.component.html
<app-reactive-form-example></app-reactive-form-example>
您可以运行 npm start
命令并在 Web 浏览器中与您的输入进行交互。 如果您在电话字段中输入少于或多于 10 个字符,则会显示错误消息。
此时,您有一个使用反应形式的函数的自定义验证器。
结论
在本文中,向您介绍了在 Angular 应用程序中为模板驱动表单和反应式表单添加自定义验证。
自定义验证允许您确保用户提供的值符合您的期望。
要更深入地了解这篇文章中的概念,请访问 this post on Providers 和 了解 AbstractControl。