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

介绍

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

有几种内置的验证喜欢requiredemailpattern,和minLength还可以开发自定义验证器来解决内置验证器未处理的功能。

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

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

具有无效电话号码的输入字段的屏幕截图。 输入以红色边框突出显示,并且有一条错误消息指示该字段期望电话号码值为 10 位长。

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

屏幕截图:具有有效电话号码的输入字段。 输入以蓝色边框突出显示,并且没有错误消息。

在本教程中,您将为 Angular 应用程序中的电话号码输入字段构建一个自定义验证器。

先决条件

要完成本教程,您需要:

本教程已通过 Node v15.2.1、npmv6.14.8、@angular/corev11.0.0 和@angular/formsv11.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.tsphone-number-validator.directive.spec.ts它还将添加PhoneNumberValidatorDirectiveapp.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;
  }
}

此代码创建它实现了一个指令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.tstemplate-driven-form-example.component.html文件。它还将添加TemplateDrivenFormExampleComponentapp.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 在/errors属性中添加了验证函数的返回值如果/属性不为空,则表单无效。如果属性为空,则表单有效。FormControlNgModelerrorsFormControlNgModelerrors

要在模板驱动的表单中使用该指令,请打开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

然后,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文件。它还将添加ReactiveFormExampleComponentapp.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)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 应用程序中的模板驱动表单和反应式表单添加自定义验证。

自定义验证允许您确保用户提供的值符合您的期望。

要更深入地了解这篇文章中的概念,请访问这篇文章Providers阅读有关AbstractControl.

觉得文章有用?

点个广告表达一下你的爱意吧 !😁