为了账号安全,请及时绑定邮箱和手机立即绑定

响应式表单之验证表单

添加验证器

Angular 的内置验证器由 Validators 模块提供,如果想要为 FormControl 对象添加验证器,直接将验证器作为 FormControl 的第二个参数即可。

下面例子中列举了比较常用的内置验证器及其使用形式:

例子:

form.component.html

<form [formGroup]="myGroup">
  <ul>
    <li>
      姓名:<input type="text" formControlName="name">
    </li>
    <li>
      性别:<input type="text" formControlName="sex">
    </li>
    <li>
      年龄:<input type="number" formControlName="age">
    </li>
    <li>
      血型:<input type="text" formControlName="type">
    </li>
  </ul>
</form>

form.component.ts

import { Component, OnInit } from '@angular/core';

// 导入校验接口 Validators
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss']
})
export class FormComponent implements OnInit {

  myGroup!: FormGroup;

  constructor(
    private fb: FormBuilder,
  ) { }

  ngOnInit() {

    this.myGroup = this.fb.group({
        // 添加必填校验:required
        name:['', Validators.required],
        // 添加单个校验规则的其他方法:
        // new FormControl('', Validators.required);
        // this.fb.control('', Validators.required);

        // 添加字符长度校验:minLength()、maxLength()
        sex:['', [Validators.required, Validators.maxLength(1)]],
        // 添加多个校验规则的其他方法:
        // new FormControl('', [Validators.required, Validators.maxLength(1)]);
        // this.fb.control('', [Validators.required, Validators.maxLength(1)]);

        // 添加数值大小校验:min()、max()
        age: ['', [Validators.required, Validators.min(6)]],

        // 添加正则表达式:pattern()
        type:['', [Validators.pattern('[a-zA-Z ]*'), Validators.maxLength(2)]]
    });

  }

}

自定义验证器

我们也可以创建自己的验证器。

项目结构:
图片描述

例子:

form-validators.service.ts

import { Injectable } from '@angular/core';
import { ValidatorFn, FormControl, AbstractControl } from '@angular/forms';

@Injectable()
export class FormValidatorsService {

constructor() { }

  // c: FormControl 或者 c: AbstractControl 都指向需要验证的内容
  // AbstractControl 是 FormControl 的基类,因此它们共享 value 属性,使用哪个都可以
  // 如果验证失败,返回 {[key: string]: boolean} 对象,key 为错误代码,自定义即可,boolean 为 true
  // 如果验证成功,返回 null
  phoneNumberValidator(c: FormControl): {[key: string]: boolean} | null {

    // 验证手机号是否以数字'1'开头
    if (!c.value.match(/^1/)) {
      return { 'phoneNumber': true };
    }
      return null;
  }

  // 验证器函数传参的写法
  areaNumberValidator(param: string): ValidatorFn {
    return (c: AbstractControl): {[key: string]: boolean} | null => {

      // 验证座机区号是否为 param
      if(!c.value.startsWith(param)) {
        return { 'areaNumber': true};
      }
        return null;
    }
  }

}

form.component.html

<form [formGroup]="myGroup">
  <p>
    手机:<input type="tel" formControlName="phoneNumber">
  </p>
  <p>
    座机:<input type="tel" formControlName="areaNumber">
  </p>
</form>

form.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';

// 导入自定义验证器 FormValidatorsService
import { FormValidatorsService } from './service/form-validators.service'

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss'],

  // 将 FormValidatorsService 注入组件
  providers: [
    FormValidatorsService
  ],
})
export class FormComponent implements OnInit {

  myGroup!: FormGroup;

  constructor(
    private fb: FormBuilder,

    // 初始化 FormValidatorsService
    private formValidators: FormValidatorsService
  ) { }

  ngOnInit() {

    this.myGroup = this.fb.group({
      // 添加 phoneNumberValidator 验证器
      phoneNumber:['', [Validators.required, this.formValidators.phoneNumberValidator]],
      
      // 添加 areaNumberValidator 验证器,该验证器可以传参
      areaNumber:['', [Validators.required, this.formValidators.areaNumberValidator('0411')]],
    });

  }

}

检查验证器的有效性

FormControl 与 FormGroup 的关系

FormControl 与 FormGroup 都继承自基类 AbstractControl,因此,FormControl 与
FormGroup 共享着 AbstractControl 的属性和方法,比如 value、valid、valueChanges() 等等。
FormControl 封装了单个输入字段的值和状态,比如字段是否有效,是否被修改过或者是否有错误等等。
而 FormGroup 的意义在于管理多个 FormControl,为一组 FormControl 提供总的接口,比如我们要验证多个 FormControl 是否有效(valid 属性),就需要遍历每一个 FormControl,比较繁琐,这种情况下,使用 FormGroup 就可以轻松地解决问题。

检查整个表单的有效性

结合我上面的介绍,我们通过 FormGroup 的属性 valid 就可以检查整个表单的有效性,只有当所有的 FormControl 都有效时,这个 FormGroup 才会有效。

例子:

form.component.html

<form [formGroup]="myGroup">
  <p>
    手机:<input type="tel" formControlName="phoneNumber">
  </p>
  <p>
    座机:<input type="tel" formControlName="areaNumber">
  </p>
  <p style="color: red;">{{ errMsg }}</p>
  
  <button (click)="save()">提交</button>
</form>

form.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss']
})
export class FormComponent implements OnInit {

  myGroup!: FormGroup;
  errMsg!: string;

  constructor(
    private fb: FormBuilder
  ) {}

  ngOnInit() {
    
    this.myGroup = this.fb.group({
      phoneNumber:['', Validators.required],
      areaNumber:['', Validators.required],
    });
   
  }

  // 验证整个表单的有效性并显示错误信息
  save() :boolean{
    if(!this.myGroup.valid){
      this.errMsg = '验证未通过!';
      return false;
    }
    console.log(this.myGroup.value);
    this.errMsg = '';
    return true;
  }

}

图片描述

检查单个字段的有效性

很多时候,我们需要知道哪个字段无效,导致了验证的失败,所以,检查单个字段的有效性并显示错误消息是更加实际的需求。
为单个 FormControl 进行验证,我们必须为每个字段定义一个变量,并为变量添加 getter 方法。

例子:

form.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss']
})
export class FormComponent implements OnInit {

  myGroup!: FormGroup;
  errMsg!: string;

  // 声明变量 phoneNumber、areaNumber  
  // 这样,在组件和模板中,就可以到处引用变量
  get phoneNumber(){
    // 使用 FormGroup 的 get 方法或 controls 获取单个字段
    return this.myGroup.get('phoneNumber');
    // return this.myGroup.controls['phoneNumber'];
  }
  get areaNumber(){
    return this.myGroup.get('areaNumber');
    // return this.myGroup.controls['areaNumber'];
  }

  constructor(
    private fb: FormBuilder
  ) {}

  ngOnInit() {
    
    this.myGroup = this.fb.group({
      phoneNumber:['', Validators.required],
      areaNumber:['', Validators.required],
    });
   
  }

  save() :boolean{
    if(!this.myGroup.valid){
      console.log('保存失败');
      return false;
    }
    
    console.log(this.myGroup.value);
    return true;
  }

}

form.component.html

<form [formGroup]="myGroup">
  <p>
    手机:<input type="tel" formControlName="phoneNumber">
    
    <!-- 在模板中引用变量 -->
    <!-- phoneNumber.valid:验证 phoneNumber 是否有效 -->
    <!-- phoneNumber.touched:验证 phoneNumber 是否被修改 -->
    <i style="color: red;" *ngIf="!phoneNumber?.valid && phoneNumber?.touched">手机验证未通过!</i>
  </p>
  <p>
    座机:<input type="tel" formControlName="areaNumber">
    <i style="color: red;" *ngIf="!areaNumber?.valid && areaNumber?.touched">座机验证未通过!</i>
  </p>

  <button (click)="save()">提交</button>
</form>

图片描述

特定验证

一个字段可能添加了很多验证器,对于失败的原因,我们更希望根据不同的原因提示不同的消息。
我们可以使用 hasError() 检查哪些验证失败。

例子:

form.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormControl, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss']
})
export class FormComponent implements OnInit {

  myGroup!: FormGroup;
  errMsg!: string;

  get phoneNumber(){
    return this.myGroup.get('phoneNumber');
  }

  constructor(
    private fb: FormBuilder
  ) {}

  ngOnInit() {
    
    this.myGroup = this.fb.group({
      phoneNumber:['', [Validators.required, Validators.pattern('^[0-9]*$')]
                ]
    });
   
  }

  save() :boolean{
    if(!this.myGroup.valid){
      console.log('保存失败');
      return false;
    }
    
    console.log(this.myGroup.value);
    return true;
  }

}

form.component.html

<form [formGroup]="myGroup">
  <p>
    手机:<input type="tel" formControlName="phoneNumber">
    <span style="color: red;" *ngIf="!phoneNumber?.valid && phoneNumber?.touched">
      <i *ngIf="phoneNumber?.hasError('required')">必填!</i>
      <i *ngIf="phoneNumber?.hasError('pattern')">必须是数字!</i>
    </span>
  </p>

  <button (click)="save()">提交</button>
</form>

图片描述


end

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
Web前端工程师
手记
粉丝
1.4万
获赞与收藏
860

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消