在上一篇文章中提到了表单,只说了表单的数据绑定,这一篇文章主要讲一下表单验证,为什么把表单单独拿出来学习,主要是因为,表单是商业应用的支柱,我们用它来执行登录、求助、下单、预订机票、安排会议,以及不计其数的其它数据录入任务,使用频率非常高。所以这块的重要性就显而易见了。
正文开始,这篇文章还是适合初学者,如果是大神,请指正不足:
先来看一下最终的样子:
表单很简单,模拟新增客户,用到表单的不少控件,
首先,要使用angular 的表单的一些控件,在使用ngModel
做双向数据绑定之前,得先导入FormsModule
, 把它加入 Angular 模块的imports
列表。
在加载之前写组件。app.module.ts主文件代码如下:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; //引入表单模块 import { AppComponent } from './app.component'; import { UserForm } from './form.component'; // 引入自定义的组件 @NgModule({ imports: [ BrowserModule ,FormsModule], declarations: [ AppComponent,UserForm], bootstrap: [ AppComponent ] }) export class AppModule { }
下面我们主要看一下表单这个组件内部的一些细节:
1 import { Component } from '@angular/core'; 2 3 @Component({ 4 selector:'hero-form', 5 template:` 6 <h2>FORM 表单</h2> 7 <hr /> 8 <div class="container"> 9 <div class="row"> 10 <div class="col-sm-6 col-sm-offset-3"> 11 <h4>客户管理</h4> 12 <form #forms="ngForm"> 13 <div class="alert alert-danger" [hidden]="forms.form.valid">表单填写不合法</div> 14 <div class="form-group"> 15 <label [class.text-danger]="!name.valid && forms.form.controls.name.touched">姓名</label> 16 <input type="text" class="form-control" name="name" [(ngModel)]="model.name" #name="ngModel" required> 17 </div> 18 <div class="form-group"> 19 <label [class.text-danger]="!sex.valid && forms.form.controls.sex.touched">性别</label> 20 <select class="form-control" [(ngModel)]="model.sex" required name="sex" #sex="ngModel"> 21 <option *ngFor="let s of sexs" [ngValue]="s">{{s}}</option> 22 </select> 23 </div> 24 <div class="form-group"> 25 <label>来源</label> 26 <div> 27 <label class="checkbox-inline" *ngFor="let f of froms"> 28 <input type="radio" [value]="f" name="from" [(ngModel)]="model.from" #from="ngModel" required> {{f}} 29 </label> 30 </div> 31 </div> 32 <div class="form-group"> 33 <label>意向产品</label> 34 <div> 35 <label class="checkbox-inline" *ngFor="let p of model.mayBuy"> 36 <input type="checkbox" [(ngModel)]="p.chose" [value]="p.pid" name="mayBuy" required> {{p.pname}} 37 </label> 38 </div> 39 </div> 40 <button type="button" (click)="submit(forms.form)" [class.btn-danger]="!forms.form.valid" [disabled]="!forms.form.valid" class="btn btn-primary">提交</button> 41 </form> 42 </div> 43 </div> 44 </div> 45 ` 46 }) //这里有个小坑,如果这里按习惯加一个分号“;”,那就挂了,不能编译 47 48 export class UserForm { 49 sexs = ['男', '女','保密']; 50 products = [ 51 { 52 pid:'p_001', 53 pname:'产品A', 54 chose:false 55 }, 56 { 57 pid:'p_001', 58 pname:'产品B', 59 chose:false 60 }, 61 { 62 pid:'p_001', 63 pname:'产品C', 64 chose:false 65 }, 66 { 67 pid:'p_001', 68 pname:'产品D', 69 chose:false 70 } 71 ]; 72 froms = ['新增客户','老客户介绍']; 73 model = { 74 name:'', 75 sex:'', 76 from:'', 77 mayBuy:this.products 78 }; 79 submitted = false; 80 81 submit(a:any){ 82 console.log(this.model,a) 83 } 84 }
普通表单结构以及数据的双向绑定,就不多说了,主要说一下表单验证这块,即红色代码的地方。
交代一下基础概念,在ng 的表单模块中,单个控件(如:input)都会被跟踪状态,并且会在该控件上增加相应的class:
1)、控件是否已经被访问过:
是:touched;class:ng-touched
否:untouched; class:ng-untouched
2)、控件的值是否被修改过:
是:dirty;class:ng-dirty
否:pristine;class:ng-pristine
3)、控件的值是否合法:
是:valid;class:ng-valid
否:invalid;class:ng-invalid
整体表单也存在以上的3中状态,表单的验证证是通过这些跟踪的不同状态完成的。那么怎么访问到这些状态呢?
你可能已经注意到在form标签上有这样一段代码:
<form #forms="ngForm">
是的,#forms这个就是模版引用变量,上一篇文章提到过,这里只是把#forms初始化为 "ngForm";
现在我们就可以通过forms这个对象访问到我们需要的状态了,如果你不知道forms里都有啥,怎么用,那你就写个方法,把它打印出来,(click)="submit(forms)" 就可以了。
还有一个要注意的点,就是针对类似
<input type="text" class="form-control" name="name" [(ngModel)]="model.name" #name="ngModel" required>
这样的,name属性是必须要添加的,如果要对单个控件进行验证,我们可以加上模版引用变量#name="ngModel"快速访问到这个控件。
如果你需要正则表达式验证,只需加入pattern属性即可;
<input type="text" class="form-control" pattern="[a-zA-Z ]*" [(ngModel)]="model.name" name="name" />
以上述代码为例主要有以下几个点:
1、整体表单的合法性验证:
代码:forms.form.STATE,例如:forms.form.valid;forms.form.invalid
2、单个表单控件验证:
以这段代码为例:
1 <div class="form-group"> 2 <label [class.text-danger]="!name.valid && forms.form.controls.name.touched">姓名</label> 3 <input type="text" class="form-control" name="name" [(ngModel)]="model.name" #name="ngModel" required> 4 </div>
这里的label的显示样式的判断条件其实是两种判断方法,
1)、!name.valid这个是使用模板引用变量来判断的;
2)、forms.form.controls.name.touched是使用forms.form这个对象判断的。
注意:forms.form这个对象里有很多子对象,这里使用的是form下controls这个对象查找到name判断的,至于是否应该controls这个子对象,有待研究。
本文到此结束,只是表单的一些初级应用,如果想了解更多,请点击这里查看API文档。
欢迎大家对本文所涉及的内容进行探讨,对有误的地方进行指正。
感谢阅读。