网站首页 » 前端开发 » Angular 2+ » Angular 2+ 表单验证
上一篇:
下一篇:

Angular 2+ 表单验证

前言

表单验证远处不在,但你知道在 Angular 2+ 中怎么用了吗?或许你早已知道,或许你还一头雾水,知道的可以跳过,不知道的可以留步。

表单验证之旅

在《Angular 2+ 表单》 已经有分享过表单的验证了,但只是模板驱动验证的,本文我们换一种方式来实现同样的功能,这种方式叫做响应式表单的验证,不管叫法如何变,但关键的东西还是一亲的:验证用户输入的合法性。

响应式表单的验证

下面用一个图来演示本文所要做的东西:

Angular 2+ 响应式表单的验证

下面我们直接来看代码:

在做响应式表单验证之前,我们首先需要在 app.module.ts 中引入 ReactiveFormsModule:

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';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    ReactiveFormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

接下来我们看看表单的结构页:

app.component.html
<div class="container">
  <div [hidden]="submitted">
    <h1>My Form</h1>
    <form [formGroup]="registerForm" #myForm="ngForm" (ngSubmit)="onSubmit()">
      <div class="form-group">
        <label for="name">Name</label>
        <input type="text" class="form-control" id="name" formControlName="name" name="name" [(ngModel)]="person.name" required>
      </div>
      <div *ngIf="name.invalid && ( name.dirty || name.touched )" class="alert alert-danger">
        <span *ngIf="name.errors.required">name is required</span>
        <span *ngIf="name.errors.minlength">minlength is 4</span>
      </div>
      <div class="form-group">
        <label for="age">Age</label>
        <input type="number" class="form-control" id="age" formControlName="age" name="age" [(ngModel)]="person.age">
      </div>
      <div *ngIf="age.invalid && ( age.dirty || age.touched )" class="alert alert-danger">
        <span *ngIf="age.errors.required">age is required</span>
      </div>
      <div class="form-group">
        <label for="sex">Sex</label>
        <select class="form-control" id="sex" formControlName="sex" name="sex" [(ngModel)]="person.sex">
          <option value=""></option>
          <option *ngFor="let sex of sexData" [value]="sex">{{sex}}</option>
        </select>
      </div>
      <div *ngIf="sex.invalid && ( sex.dirty || sex.touched )" class="alert alert-danger">
        <span *ngIf="sex.errors.required">sex is required</span>
      </div>
      <button type="button" class="btn btn-default" (click)="reset(myForm)">Reset</button>
      <button type="submit" class="btn btn-success" [disabled]="myForm.form.invalid">Submit</button>
    </form>
  </div>
  <div [hidden]="!submitted">
    <h2>You submitted the following:</h2>
    <div class="row">
      <div class="col-xs-3">Name</div>
      <div class="col-xs-9  pull-left">{{ person.name }}</div>
    </div>
    <div class="row">
      <div class="col-xs-3">Age</div>
      <div class="col-xs-9 pull-left">{{ person.age }}</div>
    </div>
    <div class="row">
      <div class="col-xs-3">Sex</div>
      <div class="col-xs-9 pull-left">{{ person.sex }}</div>
    </div>
    <br>
    <button class="btn btn-primary" (click)="submitted=false">Edit</button>
  </div>
</div>

最后出场的肯定是压轴戏了:

app.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  submitted = false;

  sexData = ['男', '女'];
  onSubmit() {
    this.submitted = true;
  }
  reset(myForm) {
    myForm.reset();
  }
  registerForm: FormGroup;
  person: any = {};
  ngOnInit(): void {
    this.registerForm = new FormGroup({
      'name': new FormControl('', [
        Validators.required,
        Validators.minLength(4),
      ]),
      'age': new FormControl('', Validators.required),
      'sex': new FormControl('', Validators.required)
    });
  }

  get name() { return this.registerForm.get('name'); }
  get age() { return this.registerForm.get('age'); }
  get sex() { return this.registerForm.get('sex'); }
}

FormControl 的第一个参数为初始值,可以不填,第二个参数就是验证机制,可以是一个,也可以是多个,多个的时候可以用数组的形式表示。

本例子基本 Boostrap UI 框架来做的,你可以在 index.html 中改入这个 UI 库。

送温暖

  • FormControl:为单个表单控件提供支持的类,可用于跟踪控件的值和验证状态
  • FormControl:包含一组 FormControl 实例,可用于跟踪 FormControl 组的值和验证状态
  • Validators:Validators 中包含了内置的验证规则,如:Validators.required

自定义验证器

很多时候 Angular 2+ 中内置的验证器很难满足我们的需求,所以我们有必要自己写一些自定义的验证器,下面这个例子直接从官方中拷贝过来的,我们可以先把这个例子了解透,然后就可以很容易地写自己的验证器了。效果来基本跟上面的一致,但第一个输入框的限制多了一项,输入内容中不能含有“来来”。

Angular 2+ 自定义验证器

先把验证器写好,封装成指令。

forbbiden-name.directive.ts
import { Directive, Input } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn, Validators } from '@angular/forms';

export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
    return (control: AbstractControl): { [key: string]: any } => {
        const forbidden = nameRe.test(control.value);
        return forbidden ? { 'forbiddenName': { value: control.value } } : null;
    };
}

@Directive({
    selector: '[appForbiddenName]',
    providers: [{ provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true }]
})

export class ForbiddenValidatorDirective implements Validator {
    @Input() forbiddenName: string;
    validate(control: AbstractControl): { [key: string]: any } {
        return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control) : null;
    }
}

Angular在验证流程中的识别出指令的作用,是因为指令把自己注册到了NG_VALIDATORS 提供商中,该提供商拥有一组可扩展的验证器。

我们只需要在前面例子的 .html 代码中添加一个对应的错误提示信息就可以了。

app.component.html
<div class="container">
  <div [hidden]="submitted">
    <h1>My Form</h1>
    <form [formGroup]="registerForm" #myForm="ngForm" (ngSubmit)="onSubmit()">
      <div class="form-group">
        <label for="name">Name</label>
        <input type="text" class="form-control" id="name" formControlName="name" name="name" [(ngModel)]="person.name" required>
      </div>
      <div *ngIf="name.invalid && ( name.dirty || name.touched )" class="alert alert-danger">
        <div *ngIf="name.errors.required">name is required</div>
        <div *ngIf="name.errors.minlength">minlength is 4</div>
        <div *ngIf="name.errors.forbiddenName">forbidden name</div>
      </div>
      <div class="form-group">
        <label for="age">Age</label>
        <input type="number" class="form-control" id="age" formControlName="age" name="age" [(ngModel)]="person.age">
      </div>
      <div *ngIf="age.invalid && ( age.dirty || age.touched )" class="alert alert-danger">
        <span *ngIf="age.errors.required">age is required</span>
      </div>
      <div class="form-group">
        <label for="sex">Sex</label>
        <select class="form-control" id="sex" formControlName="sex" name="sex" [(ngModel)]="person.sex">
          <option value=""></option>
          <option *ngFor="let sex of sexData" [value]="sex">{{sex}}</option>
        </select>
      </div>
      <div *ngIf="sex.invalid && ( sex.dirty || sex.touched )" class="alert alert-danger">
        <span *ngIf="sex.errors.required">sex is required</span>
      </div>
      <button type="button" class="btn btn-default" (click)="reset(myForm)">Reset</button>
      <button type="submit" class="btn btn-success" [disabled]="myForm.form.invalid">Submit</button>
    </form>
  </div>
  <div [hidden]="!submitted">
    <h2>You submitted the following:</h2>
    <div class="row">
      <div class="col-xs-3">Name</div>
      <div class="col-xs-9  pull-left">{{ person.name }}</div>
    </div>
    <div class="row">
      <div class="col-xs-3">Age</div>
      <div class="col-xs-9 pull-left">{{ person.age }}</div>
    </div>
    <div class="row">
      <div class="col-xs-3">Sex</div>
      <div class="col-xs-9 pull-left">{{ person.sex }}</div>
    </div>
    <br>
    <button class="btn btn-primary" (click)="submitted=false">Edit</button>
  </div>
</div>

在响应式表单验证组件中使用它。

app.component.ts
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { forbiddenNameValidator } from './forbidden-name.directive';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  submitted = false;
  sexData = ['男', '女'];
  onSubmit() {
    this.submitted = true;
  }
  reset(myForm) {
    myForm.reset();
  }
  registerForm: FormGroup;
  person: any = {};
  ngOnInit(): void {
    this.registerForm = new FormGroup({
      'name': new FormControl('', [
        Validators.required,
        Validators.minLength(4),
        forbiddenNameValidator(/来来/i)
      ]),
      'age': new FormControl('', Validators.required),
      'sex': new FormControl('', Validators.required)
    });
  }
  get name() { return this.registerForm.get('name'); }
  get age() { return this.registerForm.get('age'); }
  get sex() { return this.registerForm.get('sex'); }
}

表单验证就到这里,希望能帮到你!

  • 微信扫一扫,赏我

  • 支付宝扫一扫,赏我

声明

原创文章,不经本站同意,不得以任何形式转载,如有不便,请多多包涵!

本文永久链接:http://yunkus.com/angular-core-knowledge-form-validation/

Leave a Reply

Your email address will not be published. Required fields are marked *

评论 END