强大的 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性能优化 创建文档碎片(document.createDocumentFragment)
Jul 13 Javascript
判断多个input type=file是否有已经选择好文件的代码
May 23 Javascript
js捕获鼠标滚轮事件代码
Dec 16 Javascript
jQuery插件EasyUI设置datagrid的checkbox为禁用状态的方法
Aug 05 Javascript
JS实用的带停顿的逐行文本循环滚动效果实例
Nov 23 Javascript
前端开发之CSS原理详解
Mar 11 Javascript
VUE多层路由嵌套实现代码
May 15 Javascript
Easyui ueditor 整合解决不能编辑的问题(推荐)
Jun 25 Javascript
微信小程序自定义单项选择器样式
Jul 25 Javascript
vue 中 elment-ui table合并上下两行相同数据单元格
Dec 26 Javascript
JS实现简易日历效果
Jan 25 Javascript
JS数组方法some、every和find的使用详情
Oct 05 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
php中模拟POST传递数据的两种方法分享
2011/09/16 PHP
php获取bing每日壁纸示例分享
2014/02/25 PHP
PHP错误机制知识汇总
2016/03/24 PHP
PHP获取对象属性的三种方法实例分析
2019/01/03 PHP
js 新浪的一个图片播放图片轮换效果代码
2008/07/15 Javascript
不要小看注释掉的JS 引起的安全问题
2008/12/27 Javascript
Mootools 1.2教程 事件处理
2009/09/15 Javascript
jQuery截取指定长度字符串代码
2014/08/21 Javascript
jquery通过ajax加载一段文本内容的方法
2015/01/15 Javascript
jQuery EasyUI Pagination实现分页的常用方法
2016/05/21 Javascript
jQuery选择器实例应用
2017/01/05 Javascript
微信小程序 定位到当前城市实现实例代码
2017/02/23 Javascript
AngularJS路由切换实现方法分析
2017/03/17 Javascript
详解如何使用vue-cli脚手架搭建Vue.js项目
2017/05/19 Javascript
JS实现的全排列组合算法示例
2017/10/09 Javascript
用node-webkit把web应用打包成桌面应用(windows环境)
2018/02/01 Javascript
webstrom Debug 调试vue项目的方法步骤
2018/07/17 Javascript
puppeteer实现html截图的示例代码
2019/01/10 Javascript
Vue.js构建你的第一个包并在NPM上发布的方法步骤
2019/05/01 Javascript
详解nuxt 微信公众号支付遇到的问题与解决
2019/08/26 Javascript
Openlayers显示地理位置坐标的方法
2020/09/28 Javascript
[01:15:00]LGD vs Mineski Supermajor 胜者组 BO3 第一场 6.5
2018/06/06 DOTA
paramiko模块安装和使用(远程登录服务器)
2014/01/27 Python
python中sort sorted reverse reversed函数的区别说明
2020/05/11 Python
HTML5 localStorage使用总结
2017/02/22 HTML / CSS
C#笔试题
2015/07/14 面试题
优秀小学生家长评语
2014/01/30 职场文书
土木工程专业本科生求职信
2014/10/01 职场文书
2014年最新离婚协议书范本
2014/10/11 职场文书
2015年教师新年寄语
2014/12/08 职场文书
离职感谢信
2015/01/21 职场文书
十月围城观后感
2015/06/08 职场文书
mybatis调用sqlserver存储过程返回结果集的方法
2021/05/08 SQL Server
分析Java中Map的遍历性能问题
2021/06/26 Java/Android
在vue中import()语法不能传入变量的问题及解决
2022/04/01 Vue.js
Java线程的6种状态与生命周期
2022/05/11 Java/Android