模板式表单

NgForm、NgModel、NgModelGroup是FormModule里的内容,NgForm会自动拦截标准的表单处理事件(eg.提交),angular用ngSubmit代替标准的表单提交NgForm隐式的创建一个FormGroup类的实例,代表表单的数据模型,用来存储表单数据,标有这个指令的表单会自动发现标有NgModel指令的表单子元素,并将它们的值添加到数据模型中

<div ngForm>
...
</div>
等同于
<form>
...
</form>

如果不想让angular管理你的表单,需要在表单标签里添加ngNoForm,此时浏览器默认行为生效(eg. action、post)

<form ngNoForm>
...
</form>

模板本地变量(#开头 eg.#myForm)

表单被模板本地变量引用,以便在模板中访问NgForm的实例

<form #myForm = "ngForm" (ngSubmit) = "onSubmit(myForm.value)">
...已经拿到NgForm创建的对象了<input type="text" ngModel><input type="text" ngModel><input type="text" ngModel>
</form>
<div>
使用:{{myForm.value | json}}
value保存着所有表单字段(仅限标有ngModel的字段)里的当前值
</div>onSubmit(value: any) {
console.log(value);
}

ngModel会隐式的创建一个FormControl,代表字段的数据模型,在ngForm的表单里这个指令不需要用括号[()]括起来, 但需要为添加这个指令的字段添加一个name属性

<form #myForm = "ngForm" (ngSubmit) = "onSubmit(myForm.value)">...通过onSubmit函数传参,已经拿到NgForm创建的对象了<input type="text" ngModel name="username"><input type="password" ngModel name="password"><input type="password" ngModel name="repassword">
</form>

name属性会成为前面所说value对象的一个属性名

标有ngModel的字段也可以用模板本地变量引用,从而获取它的值

<input type="text" ngModel name="username" #username = "ngModel">
<p>{{username.value}}
</p>

NgModelGroup,是表单的一部分,允许将一部分表单字段组织在一起(比如密码和确认密码的input),形成更清晰的层次关系,隐式创建一个FormGroup类的实例,。。看代码更直接。。。(它的value值会在NgForm表单的那个value表现为一个嵌套的对象,所有NgModelGroup的 子属性是嵌套对象的子属性)

响应式表单

FormControl保存着当前元素的值以及校验状态,是否被修FormGroup

username:FormControl = new FormControl("aaa")
参数表示当前元素初始值

FormGroup是多个FormControl的集合,若其中一个FormControl无效则整个FormGroup无效

username:FormControl = new FormControl("aaa");
formGroup: FormGroup = new FormGroup({form: new FormControl(),to: new FormControl()
})

FormArray与FormGroup类似,但是它有一个额外的长度属性,FormGroup代表表单的固定子集,而FormArray代表一个可以增长的集合,比如让用户输入多个Email地址

FormArray中的FormControl是没有相关的key,只能通过序号(0 1 2 3…)访问

emails: FormArray = new FormArray([new FormControl("a@a.com"),new FormControl("b@a.com")
]);

相关指令,都来自reactiveFormsModule模块

第二列是属性绑定,FormArray不能通过属性绑定来写,第三列不需要用属性绑定语法

响应式表单指令都是form开头的,,,,响应式表单可以直接访问数据模型的类,只能在代码中操作,模板式表单是只能在模板中操作

html

<!-- 注意括号的问题,[formGroup]的值是后台的一个属性,而formGroupName是字符串-->
<form [formGroup] = "formModel" (submit) = "onSubmit"><input type="text" formControlName = "username"><div formGroupName = "dateRange">起始日期:<input type="date" formControlName="form">截止日期:<input type="date" formControlName="to"></div><div><ul formArrayName = "emails"><li *ngFor = "let e of this.formModel.get("emails").controls; let i = index;"><input type="text" [formControlName] = "i"></li></ul><button (click) = "addEmail()">增加Email</button></div><div><button type= "submit">保存</button></div>
</form> 

ts

formModel: FormGroup = new FormGroup({username:new FormControl("aaa"),dateRange: new FormGroup({form: new FormControl(),to: new FormControl()}),emails: FormArray = new FormArray([new FormControl("a@a.com"),new FormControl("b@a.com")])
})
addEmail(){let emails = this.formModel.get("emails") as FormArray;//拿到一个FormArray类型的对象emails.push(new FormControl())
}
onSubmit() {console.log(this.formModel.value);
}

在formgroup里要用formControlName

响应式的注册表单

html

<form [formGroup]="formModel" (submit)="onSubmit()"><div>用户名<input type="text" formControlName="username"></div><div>手机号<input type="text" formControlName="mobile"></div><div formGroupName="passwordsGroup"><div>密码<input type="password" formControlName="password"></div><div>确认密码<input type="password" formControlName="pconfirm"></div></div><button type="submit">注册</button>
</form>

ts

import {FormControl, Validators, FormGroup, FormArray, FormBuilder} from '@angular/forms';formModel: FormGroup;
constructor() {this.formModel = new FormGroup({username: new FormControl(),mobile: new FormControl(),passwordsGroup: new FormGroup({password: new FormControl(),pconfirm: new FormControl()})});
}
onSubmit() {console.log(this.formModel.value);
}

formBulider

简化了表单处理的语法,本身没有什么特性

ts:

 constructor(fb: FormBuilder) {this.formModel = fb.group({username: ['', [Validators.required, Validators.minLength(6)]],mobile: ['', mobileValidator, mobileAsyncValidator],passwordsGroup: fb.group({password: ['', Validators.minLength(6)],pconfirm: ['']}, {validator: equalValidator}) // 同时校验多个字段,即为FormGroup定义校验器});}
formBulider可以接受一个参数,eg. 第一个参数是formControl的初始值,第二个是校验方法,
第三个是异步校验方法,如上面的代码,
后面说校验的时候会说到,这里就先挂着,明白它是干嘛的

表单校验

angular的校验器:是一个普通的方法,接受一个参数,类型必须是AbstractControl,返回一个任意结构的对象,但这个对象的key必须是string类型,值任意

xxx(control: AbstractControl): {[key: string]:any} {return null;
}

预定义校验器,在Forms里Validators对象里,minlength ,maxlength,required, pattern,用法上面有提到

this.formModel.get("mobile").errors
// 获取到这个元素的errors属性

响应式表单校验

我们可以把这些校验器放到一个ts文件里,通过export暴露,达到通用的目的。

validator/validators.ts

import {FormControl, FormGroup} from "@angular/forms";
import {Observable} from "rxjs/Observable";
import {observable} from "rxjs/symbol/observable";
export function mobileValidator(control: FormControl):  any {var myreg =  /^1[3|4|5|7|8][0-9]{9}$/;let valid = myreg.test(control.value);console.log("mobile的校验结果是" + valid);return valid ? null : {mobile : true};
}
export function equalValidator(group: FormGroup): any {let password: FormControl = group.get('password') as FormControl;let pconfirm: FormControl = group.get('pconfirm') as FormControl;let valid:boolean = (password.value === pconfirm.value);// console.log('密码校验结果是' + valid);return valid  ? null : {equal: {descs: "两次密码不一致"} };
}

在组件中就可以引用这个方法,ide自动添加了import…如果没有就要自己添加

 passwordsGroup: fb.group({password: ['', Validators.minLength(6)],pconfirm: ['']}, {validator: equalValidator})

表单的状态提示hasError属性

[hidden] = "!formModel.hasError('required', 'username')"
[hidden] = "!formModel.hasError('mobile', 'mobile')"
/* 因为返回的对象key是mobile所以第一个参数是mobile */

如果要校验的字段是一个formGroup里的formControl,hasError属性的第二个参数就是一个数组,如下:

<div formGroupName="passwordsGroup"><div>密码<input type="password" formControlName="password"></div><div [hidden] = "!formModel.hasError('minlength', ['passwordsGroup', 'password'])">密码最小长度是6</div><div>确认密码<input type="password" formControlName="pconfirm"></div><div [hidden] = "!formModel.hasError('equal', 'passwordsGroup')">{{formModel.getError('equal', 'passwordsGroup')?.descs}}  这个插值表达式直接显示出校验器里无效时的error</div>
</div>

异步校验器

: 调用远程服务校验表单值,它返回一个可观测的流

export function mobileAsyncValidator(control: FormControl):  any {var myreg = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})) + d{8})$/;let valid = myreg.test(control.value);console.log("mobile的校验结果是" + valid);return observable.of(valid ? null : {mobile : true}).delay(5000);
}

状态字段

touched、untouched 判断是否获取过焦点
pristine(从未被改变过,值为true,反之....)、dirty(被修改过,值为true) 判断字段的值有没有被改变过
pending 正处于异步校验时这个属性为true/* touched、untouched关注的是有无聚焦,pristine、dirty关注值有没有被改变 ,
只要有一个字段聚焦则整个表单都被聚焦,所有字段都未被聚焦,表单才未被聚焦,
pristine、dirty同样*/

响应式表单状态错误提示

.eg.

/* 用户刚打开表单,所有字段都是空的显然不合法,但因为还未被用户访问所以显示错误信息不大美观,
所以字段外面的div表示只有当该字段不合法且已被访问时才显示错误信息,*/
<div [hidden] = "formModel.get('username').valid || formModel.get('username').untouched"><div [hidden] = "!formModel.hasError('required', 'username')">用户名是必填项</div><div [hidden] = "!formModel.hasError('minlength', 'username')">用户名最小长度是6</div></div><div [hidden] = "formModel.get('mobile').valid || formModel.get('mobile').pristine"><div [hidden] = "!formModel.hasError('mobile', 'mobile')">请输入正确的手机号</div>
</div>

浏览器会自动给字段加上class如ng-invalid,ng-dirty这些,这些都是根据用户输入同时改变的,可以通过这个给表单添加样式如

.ng-invalid{border: 1px solid red;
}

但这个样式是只要不合法字段都有的,而且若有一个不合法表单也不合法,所以整个表单也会有这个样式,这样子很不美丽,我们可以规定指定字段的哪个状态有哪种样式

<div>用户名<input [class.hasError]="formModel.get('username').invalid && formModel.get('username').touched" type="text" formControlName="username">
</div>

模版式表单校验

指令:
ng g directive directives/mobileValidator

指令比起组件是没有模版的,可以作为html属性来用

mobile-validator.directive.ts

import { Directive } from '@angular/core';
import {NG_VALIDATORS} from '@angular/forms';
import {mobileValidator} from '../validator/validators';@Directive({selector: '[mobile]',providers: [{provide: NG_VALIDATORS, useValue: mobileValidator, multi: true}]
})
export class MobileValidatorDirective {constructor() { }}
useValue 值是要使用的校验器函数
multi: true 表示同一个token下可以挂多个属性,因为后面密码校验的指令也挂在这个token下 ,不启用浏览器默认的校验
<form novalidate>...
</form>

equal-validator.directive.ts

import { Directive } from '@angular/core';
import {equalValidator} from '../validator/validators';
import {NG_VALIDATORS} from '@angular/forms';@Directive({selector: '[equal]',providers: [{provide: NG_VALIDATORS, useValue: equalValidator, multi: true}]
})
export class EqualValidatorDirective {constructor() { }}

reactive-register.html

<form #myForm = "ngForm" (ngSubmit) = "onSubmit(myForm.value, myForm.valid)" novalidate><div>用户名:<input ngModel required minlength="6" name="username" type="text" (input)="onMobileInput(myForm)"></div><div>手机号:<input ngModel  mobile name = "mobile" type="number"></div><div>密码:<input ngModel minlength="6"  name="password" type="password"></div><div>确认密码:<input ngModel name="pconfirm" type="password"></div></div></div><button type="submit">注册</button>
</form>

因为模版式表单无法在代码里操作数据,只有通过onSubmit函数传进去,如上面写的

(ngSubmit) = "onSubmit(myForm.value, myForm.valid)" 

reactive-register.ts

 onSubmit(value: any, valid: boolean) {console.log(valid);console.log(value);}

模版式表单状态错误提示

<div>用户名:<input ngModel required minlength="6" name="username" type="text" (input)="onMobileInput(myForm)"></div>
<div [hidden] = "!myForm.form.hasError('required', 'username')">用户名是必填项</div>
<div [hidden] = "!myForm.form.hasError('minlength', 'username')">用户名最小长度是六位</div>

和上面一样的问题,用户一进入这个错误提示都在,显得表单很不美丽,做个优化如下:

<div>用户名:<input ngModel required minlength="6" name="username" type="text" (input)="onMobileInput(myForm)"></div>
<div [hidden] = "mobileValid || mobileUntouched"><div [hidden] = "!myForm.form.hasError('required', 'username')">用户名是必填项</div><div [hidden] = "!myForm.form.hasError('minlength', 'username')">用户名最小长度是六位</div>
</div>

.ts

  mobileValid: boolean = true;mobileUntouched: boolean = true;onMobileInput(form: NgForm) {if ( form ) {console.log("ggggggggggggggggggggggggggggg");this.mobileValid = form.form.get('username').valid;this.mobileUntouched = form.form.get('username').untouched;console.log(this.mobileValid + '----------------------' + this.mobileUntouched);}}

angular4.0的模板式表单、响应式表单及其错误提示

angularjs 表单校验指令_angular4.0的模板式表单、响应式表单及其错误提示相关推荐

  1. Vue2.0 —— 由设计模式切入,实现响应式原理

    Vue2.0 -- 由设计模式切入,实现响应式原理 <工欲善其事,必先利其器> 既然点进来了,麻烦你看下去,希望你有不一样的收获. 大家好,我是vk,好久不见,今天我们一起来盘一盘关于 V ...

  2. (已更新)【S-CMS企业建站系统 v5.0 】CMS+含小程序+响应式布局+支持手机版网站+支持Q旺旺客服

    闪灵CMS企业建站系统是一款专门为企业建站提供解决方案的产品,前端模板样式主打HTML5模板,以动画效果好.页面流畅.响应式布局为特色,程序主体采用PHP+MYSQL构架,拥有独立自主开发的一整套函数 ...

  3. 什么叫基于web的网站_什么叫响应式网站?响应式网站模板教程

    随着移动端网站访问需求增加,"响应式网站"越来越受到用户欢迎.到底什么叫响应式网站呢? 其实就是网站效果可以随着屏幕尺寸大小而自适应,不会发生变形.扭曲.缺失的现象.不管你是在使用 ...

  4. 期末学生HTML个人网页作业作品~蓝色的异清轩响应式个人博客模板源码~bootstrap响应式博客网站模板html...

    HTML期末大作业~ 蓝色的异清轩响应式个人博客模板源码~学生HTML个人网页作业作品下载 ~个人主页博客网页设计制作 ~大学生个人网站作业模板 ~简单个人网页制作 临近期末, 你还在为HTML网页设 ...

  5. 期末学生HTML个人网页作业作品~蓝色的异清轩响应式个人博客模板源码~bootstrap响应式博客网站模板html

    HTML期末大作业~ 蓝色的异清轩响应式个人博客模板源码~学生HTML个人网页作业作品下载 ~个人主页博客网页设计制作 ~大学生个人网站作业模板 ~简单个人网页制作 临近期末, 你还在为HTML网页设 ...

  6. 响应式电子邮件_响应式HTML电子邮件模板

    响应式电子邮件 HTML Email templates and Email alerts are one of the integral parts of almost any site. Thes ...

  7. 【zblog模板】随然响应式导航网址目录主题

    介绍: zblog模板随然响应式导航网址目录主题免费分享,某站卖149 主题特点: 自适应导航站,SEO各个页面全局.分类.标签.文章.页面可自由配置 文章编辑里配有填写站点的[图标+网址+主标题+副 ...

  8. html5响应式高端企业disuz模板,高端html5响应式企业disuz模板(商业版)

    站长介绍 易秀购主题网分享一款,可以来丰富很多的功能,非常的方便.这款详细介绍 1.模板版本支持:discuzx3.0版本,discuzx3.1版本,discuzx3.2版本,包括[门户首页].[门户 ...

  9. matlabeig函数根据什么原理_vue3.0 源码解析二 :响应式原理(下)

    一 回顾上文 上节我们讲了数据绑定proxy原理,vue3.0用到的基本的拦截器,以及reactive入口等等.调用reactive建立响应式,首先通过判断数据类型来确定使用的hander,然后创建p ...

最新文章

  1. 学习统计学要掌握哪些知识
  2. Visual C++ 对话框增加菜单栏
  3. 爬虫——基本库的使用
  4. linux下同步库的创建
  5. ScalaTest学习笔记(一)
  6. gdb调试命令的使用及总结
  7. 【IT笔试面试题整理】二叉树中和为某一值的路径--所有可能路径
  8. python写windows程序_【Python学习】Python 写Windows Service服务程序
  9. The 46th ICPC Asia Jinan Regional Contest,2021,46届济南站热身赛
  10. 关于 if __name__ == '__main__' 的理解
  11. 566.重塑矩阵(力扣leetcode) 博主可答疑该问题
  12. 中国工业互联网相关政策汇总分析:“十四五”系列规划助力工业互联网创新融合发展[图]
  13. Android Studio快速开发之道
  14. 微信跳转浏览器html5,微信跳转浏览器或提示手机端打开HTML代码 最新
  15. 【剑指offer】解题思路汇总
  16. MediaPlayer读取手机内存文件夹权限问题
  17. jtable如何从表格中定位_ja中怎样将一个JTable表中的指定行添加到数据库
  18. 二极管、三极管、晶闸管基本知识
  19. 【028】仿猫眼、淘票票的电影后台管理和售票系统系统(含后台管理)(含源码、数据库、运行教程)
  20. 【Stephen Boyd】应用线性代数导论课件

热门文章

  1. 实体框架 5.0:空间数据类型、性能增强、数据库提升
  2. linux下mysql的启动与停止
  3. 高性能服务器机柜,TS系列网络服务器机柜
  4. maven依赖的jar包版本不一样_Maven依赖jar包冲突常见的解决方法
  5. 信息学奥赛一本通C++语言——1008:计算(a+b)/c的值
  6. 7 CO配置-控制-一般控制-维护版本
  7. python单元测试框架作用_Python自动单元测试框架
  8. stm32f407手册_入门篇 | STM32F407库函数开发L按键控制Led灯
  9. linux复制压缩文件夹,[操作系统]linux中文件或者文件夹的基本操作(复制,移动,删除,查找,压缩)...
  10. 浅谈OpenCL之Platform API(2)