如何在Angular中使用自定义表单验证

来自菜鸟教程
跳转至:导航、​搜索

介绍

验证器用于确保表单中的值满足某些要求。 它们可用于 Angular 应用程序中的 模板驱动表单反应式表单

有几个内置的验证器,例如 requiredemailpatternminLength。 还可以开发自定义验证器来解决内置验证器无法处理的功能。

例如,电话号码验证器将包含一个输入字段,除非该值长为十位,否则不会被视为有效。

这是一个电话号码输入字段的屏幕截图,该字段提供了一个九位数的无效号码:

这是一个电话号码输入字段的屏幕截图,该字段提供了一个十位数长的有效号码:

在本教程中,您将为 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.tsphone-number-validator.directive.spec.ts。 它还将 PhoneNumberValidatorDirective 添加到 app.module.ts

接下来,在代码编辑器中打开 phone-number-validator.directive.ts。 添加 ValidatorAbstractControlNG_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/formsValidator 的指令。 它将需要以下实现方法: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.tstemplate-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 / NgModelerrors 属性中添加验证函数的返回值。 如果 FormControl / NgModelerrors 属性不为空,则表单无效。 如果 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> 元素使用指令的 ngModelappPhoneNumberValidator 选择器。

如果 <input> 已经是 toucheddirty 并且验证不通过,则会发生两种情况。 首先,类 is-invalid 将应用于 <input>。 其次,将显示带有错误消息的<span>

注意: 这里的一些类 - form-groupform-controlinvalid-feedbackis-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.tsreactive-form-example.component.html 文件。 它还将 ReactiveFormExampleComponent 添加到 app.module.ts

接下来,在代码编辑器中打开 reactive-form-example.component.ts 并添加 FormBuilderAbstractControl

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)formControlNameget

然后,在代码编辑器中打开 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