介绍
验证器用于确保表单中的值满足某些要求。它们可用于Angular 应用程序中的模板驱动表单或响应式表单。
有几种内置的验证喜欢required
,email
,pattern
,和minLength
。还可以开发自定义验证器来解决内置验证器未处理的功能。
例如,电话号码验证器将包含一个输入字段,除非该值是十位数长,否则不会被视为有效。
以下是电话号码输入字段的屏幕截图,该字段提供了一个九位数长的无效号码:
这是一个电话号码输入字段的屏幕截图,该字段提供了一个十位数长的有效号码:
在本教程中,您将为 Angular 应用程序中的电话号码输入字段构建一个自定义验证器。
先决条件
要完成本教程,您需要:
- Node.js 安装在本地,您可以按照如何安装 Node.js 和创建本地开发环境来完成。
- 对设置 Angular 项目有一定的了解。
本教程已通过 Node v15.2.1、npm
v6.14.8、@angular/core
v11.0.0 和@angular/forms
v11.0.0 验证。
设置项目
出于本教程的目的,您将从使用@angular/cli
.
- 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 项目。
在模板驱动的表单中使用验证器
指令用于模板驱动表单中的验证。对于此示例,您将phone-number-validator
使用@angular/cli
.
首先,打开终端并使用@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
:
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;
}
}
此代码创建它实现了一个指令Validator
的@angular/forms
。它将需要以下实现方法: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
一个空字符串的初始值:
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 在/的errors
属性中添加了验证函数的返回值。如果/的属性不为空,则表单无效。如果属性为空,则表单有效。FormControl
NgModel
errors
FormControl
NgModel
errors
要在模板驱动的表单中使用该指令,请打开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
然后,app.module.ts
在您的代码编辑器中打开并添加FormModule
:
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
:
<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
:
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
在您的代码编辑器中打开并创建以下表单:
<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
:
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
:
<app-reactive-form-example></app-reactive-form-example>
您可以运行该npm start
命令并与您在 Web 浏览器中的输入进行交互。如果您在电话字段中输入的字符少于或多于 10 个,则会显示错误消息。
此时,您有一个使用反应形式函数的自定义验证器。
结论
在本文中,向您介绍了为 Angular 应用程序中的模板驱动表单和反应式表单添加自定义验证。
自定义验证允许您确保用户提供的值符合您的期望。
要更深入地了解这篇文章中的概念,请访问这篇文章Providers
并阅读有关AbstractControl
.