强大的 Angular 表单验证功能详细介绍


Posted in Javascript onMay 23, 2017

Angular 支持非常强大的内置表单验证,maxlength、minlength、required 以及 pattern。使用 Angular 的内置表单校验能够完成绝大多数的业务场景的校验需求,但有时我们还需要实现更为复杂的表单校验功能,这时可以使用 Angular 提供的表单自定义校验(Custom Validator)。下面,我们就来了解一下如何使用 Angular 的自定义表单校验

效果图:

强大的 Angular 表单验证功能详细介绍

1、首先,来创建我们的注册组件(register),并在模版中显示一个简单的表单

<h3 class="text-center">注册</h3>

<form>

 <div class="form-group">
 <label for="username">用户名:</label>
 <input type="text" id="username" class="form-control" >
 </div>

</form>

为了使表单看上去能够漂亮一些,在 index.html 中引入 bootstrap 样式文件:

<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

2、接下来确定我们的验证需求:

 我们希望用户名只能包含数字、字母和下划线,且不能以下划线开头

首先为 form 标签添加 formGroup 指令:

<form [formGroup]="registerForm" >

并且为 input 标签添加 formControlName 指令:

<input formControlName="username" type="text" id="username" class="form-control" >

3、在代码中定义验证规则:

从内置表单模块中导入以下类:

import { FormBuilder, FormGroup, Validators } from '@angular/forms';

其中:

      1. formBuilder 用来构建表单数据
      2. formGroup 表示表单类型
      3. Validators 包含了表单内置的验证规则,如: Validators.required

定义表单属性

registerForm: FormGroup;

定义表单验证不通过时每一项显示的错误消息(目前我们只有 username )

formErrors = {
 username: ''
 };

为每一项验证规则定义验证失败时的说明文字(表单控件可能有多条验证规则,由不通过的验证说明构成一条错误消息)

validationMessage = {
 'username': {
  'minlength': '用户名长度最少为3个字符',
  'maxlength': '用户名长度最多为10个字符',
  'required': '请填写用户名'
 }
 };

在构造函数中添加 fb 属性用来构建表单

constructor(private fb: FormBuilder) { }

添加构建表单的方法

buildForm(): void {
 // 通过 formBuilder构建表单
 this.registerForm = this.fb.group({
 /* 为 username 添加3项验证规则:
 * 1.必填, 2.最大长度为10, 3.最小长度为3
 * 其中第一个空字符串参数为表单的默认值
 */
 'username': [ '', [
  Validators.required,
  Validators.maxLength(10),
  Validators.minLength(3)
 ]]
 });

接下来我们添加一个方法用来更新错误信息

onValueChanged(data?: any) {
 // 如果表单不存在则返回
 if (!this.registerForm) return;
 // 获取当前的表单
 const form = this.registerForm;

 // 遍历错误消息对象
 for (const field in this.formErrors) {
  // 清空当前的错误消息
  this.formErrors[field] = '';
  // 获取当前表单的控件
  const control = form.get(field);

  // 当前表单存在此空间控件 && 此控件没有被修改 && 此控件验证不通过
  if (control && control.dirty && !control.valid) {
  // 获取验证不通过的控件名,为了获取更详细的不通过信息
  const messages = this.validationMessage[field];
  // 遍历当前控件的错误对象,获取到验证不通过的属性
  for (const key in control.errors) {
   // 把所有验证不通过项的说明文字拼接成错误消息
   this.formErrors[field] += messages[key] + '\n';
  }
  }
 }
 }

下面只需要在表单构建结束后初始化错误消息,并且在每次表单数据更改时更新错误消息就可以了

在 buildForm 方法中添加如下代码

// 每次表单数据发生变化的时候更新错误信息
 this.registerForm.valueChanges
 .subscribe(data => this.onValueChanged(data));

 // 初始化错误信息
 this.onValueChanged();

此时,我们已经很好的控制了错误信息,下面只需要在表单模版中添加错误信息的显示就可以了

在 input 标签下方添加如下代码:

<div *ngIf="formErrors.username" 
 class="showerr alert alert-danger" >{{ formErrors.username }}</div>

添加如下代码到表单模版的 css 中:

form {
 width: 90%;
 max-width: 45em;
 margin: auto;
 }

 .showerr {
 white-space: pre-wrap;
 }

现在我们就可以尝试运行了,在代码不报错的情况下已经能够看到非常好的效果了

如果代码报错或没有出现想象中的效果则可以参照本文结尾的完整代码进行修改

4、虽然我们已经搭建了整个布局,但是还没有实现我们的最终目的:实现自定义的表单验证
接下来我们创建一个正则验证器,新建文件 validate-register.ts :

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

 export function validateRex(type: string, validateRex: RegExp): ValidatorFn {
 return (control: AbstractControl): {[key: string]: any} => {
  // 获取当前控件的内容
  const str = control.value;
  // 设置我们自定义的验证类型
  const res = {};
  res[type] = {str}
  // 如果验证通过则返回 null 否则返回一个对象(包含我们自定义的属性)
  return validateRex.test(str) ? null : res;
 }
 }

下面我们在代码中导入此函数:

import { validateRex } from './validate-register';

修改 validationMessage 属性为:

// 为每一项表单验证添加说明文字
 validationMessage = {
 'username': {
  'minlength': '用户名长度最少为3个字符',
  'maxlength': '用户名长度最多为10个字符',
  'required': '请填写用户名',
  'notdown': '用户名不能以下划线开头',
  'only': '用户名只能包含数字、字母、下划线'
 }
 };

修改 buildForm 方法:

// 通过 formBuilder构建表单
 this.registerForm = this.fb.group({
 /* 为 username 添加 5 项验证规则:
 * 1.必填, 2.最大长度为10, 3.最小长度为3, 4.不能以下划线开头, 5.只能包含数字、字母、下划线
 * 其中第一个空字符串参数为表单的默认值
 */
 'username': [ '', [
  Validators.required,
  Validators.maxLength(10),
  Validators.minLength(3),
  validateRex('notdown', /^(?!_)/),
  validateRex('only', /^[1-9a-zA-Z_]+$/)
 ]]
 });

OK ! 大功告成了,赶紧运行代码尝试一下吧,我们可以随时添加各种验证规则,只需要修改 validationMessage 属性和 buildForm 方法即可!

如果添加多个表单控件的话还需要修改 formErrors,例如添加 password 控件则修改 formErrors 为

formErrors = {
 username: '',
 password: ''
};

大家可自行尝试一下!

完整代码:

register.component.html 

<h3 class="text-center">注册</h3>

 <form [formGroup]="registerForm" >

 <div class="form-group">
  <label for="username">用户名:</label>

  <input formControlName="username"
  type="text" id="username" #username
  class="form-control" >
  <div *ngIf="formErrors.username" class="showerr alert alert-danger" >{{ formErrors.username }}</div>
 </div>

 </form>

register.component.css:

form {
 width: 90%;
 max-width: 45em;
 margin: auto;
 }

 .showerr {
 white-space: pre-wrap;
 }

register.component.ts:

import { Component, OnInit } from '@angular/core';
 import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 import { validateRex } from './validate-register';

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

 // 定义表单
 registerForm: FormGroup;

 // 表单验证不通过时显示的错误消息
 formErrors = {
  username: ''
 };

 // 为每一项表单验证添加说明文字
 validationMessage = {
  'username': {
  'minlength': '用户名长度最少为3个字符',
  'maxlength': '用户名长度最多为10个字符',
  'required': '请填写用户名',
  'notdown': '用户名不能以下划线开头',
  'only': '用户名只能包含数字、字母、下划线'
  }
 };

 // 添加 fb 属性,用来创建表单
 constructor(private fb: FormBuilder) { }

 ngOnInit() {
  // 初始化时构建表单
  this.buildForm();
 }

 // 构建表单方法
 buildForm(): void {
  // 通过 formBuilder构建表单
  this.registerForm = this.fb.group({
  /* 为 username 添加3项验证规则:
  * 1.必填, 2.最大长度为10, 3.最小长度为3, 4.不能以下划线开头, 5.只能包含数字、字母、下划线
  * 其中第一个空字符串参数为表单的默认值
  */
  'username': [ '', [
   Validators.required,
   Validators.maxLength(10),
   Validators.minLength(3),
   validateRex('notdown', /^(?!_)/),
   validateRex('only', /^[1-9a-zA-Z_]+$/)
  ]]
  });

  // 每次表单数据发生变化的时候更新错误信息
  this.registerForm.valueChanges
  .subscribe(data => this.onValueChanged(data));

  // 初始化错误信息
  this.onValueChanged();
 }

 // 每次数据发生改变时触发此方法
 onValueChanged(data?: any) {
  // 如果表单不存在则返回
  if (!this.registerForm) return;
  // 获取当前的表单
  const form = this.registerForm;

  // 遍历错误消息对象
  for (const field in this.formErrors) {
  // 清空当前的错误消息
  this.formErrors[field] = '';
  // 获取当前表单的控件
  const control = form.get(field);

  // 当前表单存在此空间控件 && 此控件没有被修改 && 此控件验证不通过
  if (control && control.dirty && !control.valid) {
   // 获取验证不通过的控件名,为了获取更详细的不通过信息
   const messages = this.validationMessage[field];
   // 遍历当前控件的错误对象,获取到验证不通过的属性
   for (const key in control.errors) {
   // 把所有验证不通过项的说明文字拼接成错误消息
   this.formErrors[field] += messages[key] + '\n';
   }
  }
  }
 }

 }

validate-register.ts:

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

 export function validateRex(type: string, validateRex: RegExp): ValidatorFn {
 return (control: AbstractControl): {[key: string]: any} => {
  // 获取当前控件的内容
  const str = control.value;
  // 设置我们自定义的严重类型
  const res = {};
  res[type] = {str}
  // 如果验证通过则返回 null 否则返回一个对象(包含我们自定义的属性)
  return validateRex.test(str) ? null : res;
 }
 }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript 遍历对象中的子对象
Jul 03 Javascript
js面向对象 多种创建对象方法小结
May 21 Javascript
JavaScript实现统计文本框Textarea字数增强用户体验
Dec 21 Javascript
jQuery中setTimeout的几种使用方法小结
Apr 07 Javascript
jQuery实现径向动画菜单效果
Jul 17 Javascript
详解maxlength属性在textarea里奇怪的表现
Dec 27 Javascript
再谈JavaScript异步编程
Jan 27 Javascript
vue中实现methods一个方法调用另外一个方法
Feb 08 Javascript
使用JavaScript实现node.js中的path.join方法
Aug 12 Javascript
微信小程序五子棋游戏的悔棋实现方法【附demo源码下载】
Feb 20 Javascript
JavaScript变量作用域及内存问题实例分析
Jun 10 Javascript
ES6 Class中实现私有属性的一些方法总结
Jul 08 Javascript
微信小程序 侧滑删除(左滑删除)
May 23 #Javascript
最常用的jQuery表单验证(简单)
May 23 #jQuery
jquery实现简单实用的轮播器
May 23 #jQuery
vue.js 左侧二级菜单显示与隐藏切换的实例代码
May 23 #Javascript
Bootstrap多级菜单的实现代码
May 23 #Javascript
微信小程序获取用户openId的实现方法
May 23 #Javascript
详解vuex 中的 state 在组件中如何监听
May 23 #Javascript
You might like
Protoss兵种对照表
2020/03/14 星际争霸
php文件怎么打开 如何执行php文件
2011/12/21 PHP
PHP基础知识介绍
2013/09/17 PHP
跟我学Laravel之快速入门
2014/10/15 PHP
PHP6新特性分析
2016/03/03 PHP
判断目标是否是window,document,和拥有tagName的Element的代码
2010/05/31 Javascript
jquery cookie实现的简单换肤功能适合小网站
2013/08/25 Javascript
JavaScript将字符串转换为整数的方法
2015/04/14 Javascript
Node.js操作Firebird数据库教程
2016/03/04 Javascript
Function.prototype.apply()与Function.prototype.call()小结
2016/04/27 Javascript
easyui combotree加载静态数据问题(选不上)解决方法
2016/12/26 Javascript
前端自动化开发之Node.js的环境搭建教程
2017/04/01 Javascript
jQuery实现动态添加节点与遍历节点功能示例
2017/11/09 jQuery
微信小程序实现跟随菜单效果和循环嵌套加载数据
2017/11/21 Javascript
mpvue将vue项目转换为小程序
2018/09/30 Javascript
如何在Angular应用中创建包含组件方法示例
2019/03/23 Javascript
php结合js实现多条件组合查询
2019/05/28 Javascript
Vue替代marquee标签超出宽度文字横向滚动效果
2019/12/09 Javascript
vue页面加载时的进度条功能(实例代码)
2020/01/13 Javascript
微信小程序使用GoEasy实现websocket实时通讯
2020/05/19 Javascript
JavaScript实现与web通信的方法详解
2020/08/07 Javascript
基于openlayers实现角度测量功能
2020/09/28 Javascript
Python获取apk文件URL地址实例
2013/11/01 Python
Python实现简单的2048小游戏
2021/03/01 Python
如何利用CSS3制作3D效果文字具体实现样式
2013/05/02 HTML / CSS
HTML5之SVG 2D入门13—svg对决canvas及长处和适用场景分析
2013/01/30 HTML / CSS
Ralph Lauren拉夫·劳伦美国官网:带有浓郁美国气息的高品味时装品牌
2017/11/01 全球购物
德国苹果商店:MacTrade
2020/05/18 全球购物
中层竞聘演讲稿
2014/01/09 职场文书
应届大学生简历中的自我评价
2014/01/15 职场文书
高中生物教学反思
2014/02/05 职场文书
股权投资意向书
2014/04/01 职场文书
入股协议书范本
2014/04/14 职场文书
责任心演讲稿
2014/05/14 职场文书
离婚答辩状范文
2015/05/22 职场文书
Python 详解通过Scrapy框架实现爬取百度新冠疫情数据流程
2021/11/11 Python