<1>angular表单API
不同点
注意
要使用angular表单,要在app.module.ts中引入相应的模块
模版式表单:FormsModule
响应式表单:ReactiveFormsModule
<2>模版式表单
使用模版式表单时,只能使用指令来定义数据模型。
(1)NgForm
用来代表整个表单,在angular项目中,它会自动添加到每个form标签上。
示例:
1.新建一个组件
ng g component templateForm
2.修改template-form.component.html
3.修改app.component.html
4.修改app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { TemplateFormComponent } from './template-form/template-form.component';
import { NgModule } from '@angular/core';
// 引入
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
TemplateFormComponent
],
imports: [
BrowserModule,
// 添加
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
5.界面
在非angular接管的表单中,点击提交,url会变成:localhost:4200/action,
而angular接管的表单中,点击提交url不会有变化。
若想要指定form不被angular接管,可以定义:
特性:ngForm指令可以被一个模版本地变量引用,以便在模版中访问ngForm对象的实例。
例子:
1.修改template-form.component.html
{{myForm.value | json}}
2.结果
(2)NgModel
ngModel指令代表表单中的一个字段,这个指令会隐式的创建一个FormControl的实例,来代表字段的数据模型,并用这个FormControl类型的对象来存储字段的值。
在上面例子的json中,当在表单中输入值时没有加到json中显示的原因是,那些input标签并未绑定ngModel指令。
注意
在ngForm中使用ngModel不需要像普通的数据双向绑定那样用[(ngModel)]的方式,直接写ngModel即可
ngModel也可以使用模版变量来获取它的值
示例
1.
{{myForm.value | json}}
{{username.value}}
2.结果
此时再次输入用户名时就会实时反映到下面的json中
当应用为单页应用并不需要跳转网页时,往往用ngSubmit来替代form标签的提交作用
示例
1.修改template-form.component.html
{{myForm.value | json}}
{{username.value}}
2.修改template-form.component.spec.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-template-form',
templateUrl: './template-form.component.html',
styleUrls: ['./template-form.component.css']
})
export class TemplateFormComponent implements OnInit {
constructor() { }
ngOnInit() {
}
onSubmit(value:any) {
console.log(value);
}
}
(3)NgModelGroup
代表的是表单的一部分,它允许你将一些表单字段组织在一起,形成一个更清晰的层次关系,与ngForm指令类似,ngModelGroup指令也会创建一个FormGroup类的一个实例,这个实例会在ngForm对象的value属性中表现为一个嵌套的对象,所以说ngModelGroup的子属性都会变为这个嵌套对象的子属性
示例
1.修改template-form.component.html
{{myForm.value | json}}
{{username.value}}
2.结果
username就被嵌套在userInfo中成为了userInfo的一个属性。
(4)重构用户注册表单的案例
1.修改template-form.component.html
2.结果
当输入结束,点击提交时
<3>响应式表单
与模版式表单不同,创建一个响应式表单需要两步,首先需要编码来创建一个数据模型,然后需要使用些指令将模版中的html元素连接到这个数据模型上。
1、数据模型
是指用来保存表单数据的数据结构,简称模型。它由定义在angular的forms模块中的三个类组成。分别是:FormCotrol,FormGroup,FormArray
(1)FormCotrol:是构成表单的基本单位,通常情况下它用来代表一个input元素,它也可以用来代表一个更复杂的UI组件,比如说日历、下拉选择块等。FormCotrol保存着与其关联的html元素当前的值以及元素的校验状态,还有元素是否被修改过等信息。
如何创建一个FormCotrol,示例:
//其中FormCotrol接收的参数aaa是username的初始值
username:FormCotrol = new FormCotrol("aaa");
(2)FormGroup:FormGroup既可以代表表单的一部分也可以用于代表整个表单,它是多个FormCotrol的集合,FormGroup将多个FormCotrol的值和状态聚合在一起。如果一个FormCotrol是无效的,那么整个FormGroup都是无效的。
优点:在管理表单中多个相关联的字段时,使用FormGroup是很方便的,比如一个日期范围,有起始和终止日期两个input,这两个input可以放到一个FormGroup中,当其中一个任何一个字段的值无效时都会显示一个错误信息。
如何创建一个FormGroup,示例:
//FormGroup的构造函数需要一个对象
formModel:FormGroup = new FormGroup({
fromDate: new FormCotrol(),
toDate: new FormCotrol()
});
(3)FormArray:FormArray和FormGroup是类似的,但是它有一个额外的长度属性,一般来说FormGroup用来代表整个表单或者表单字段的一个固定的子集。而FormArray通常用来代表一个可以增长的字段集合。
如何创建一个FormArray,示例:
//FormArray的构造函数是一个数组
emails:FormArray = new FormArray([
new FormCotrol("[email protected]"),
new FormCotrol("[email protected]")
]);
2、响应式表单指令
使用时,上图第二列要用属性绑定语法,即[formGroup]的形式,而第三列不需要用属性绑定语法。
示例
1.修改app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ReactiveFormComponent } from './reactive-form/reactive-form.component';
// 引入响应式表单
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
ReactiveFormComponent
],
imports: [
BrowserModule,
//引入
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
2.修改reactive-form.component.ts
import { Component, OnInit } from '@angular/core';
//引入文件
import { FormGroup,FormControl,FormArray } from '@angular/forms';
@Component({
selector: 'app-reactive-form',
templateUrl: './reactive-form.component.html',
styleUrls: ['./reactive-form.component.css']
})
export class ReactiveFormComponent implements OnInit {
// 1.定义一个名为"myFormModel"的formGroup,用它来表示整个表单
myFormModel:FormGroup = new FormGroup({
// 3.声明一个formGroup,里面包含两个FormControl
dateRange: new FormGroup({
formDate:new FormControl(),
toDate:new FormControl()
}),
emails:new FormArray([
new FormControl("[email protected]"),
new FormControl("[email protected]"),
new FormControl("[email protected]")
]),
username2:new FormControl("name2")
});
// 5.定义一个名为username的FormControl
username:FormControl = new FormControl("namenamename");
constructor() { }
ngOnInit() {
}
// 2.处理保存方法,打印myFormModel的值
mySubmit(){
console.log(this.myFormModel.value);
}
// 4.增加邮箱方法
addEmail(){
let emails = this.myFormModel.get("emails") as FormArray;
emails.push(new FormControl());
}
}
3.修改reactive-form.component.html
4.结果
3、响应式表单重构用户注册表
1.修改app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ReactiveRigistComponent } from './reactive-rigist/reactive-rigist.component';
//引入响应式表单
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
ReactiveRigistComponent
],
imports: [
BrowserModule,
//引入响应式表单
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
2.修改reactive-rigist.component.html
3.修改reactive-rigist.component.ts
import { Component, OnInit } from '@angular/core';
//引入
import { FormGroup,FormControl } from '@angular/forms';
@Component({
selector: 'app-reactive-rigist',
templateUrl: './reactive-rigist.component.html',
styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {
myFormGroup:FormGroup;
constructor() {
this.myFormGroup = new FormGroup({
username:new FormControl(),
mobile:new FormControl(),
passwordGroup:new FormGroup({
pwd:new FormControl(),
pconfirm:new FormControl()
})
})
}
mySubmit(){
console.log(this.myFormGroup.value);
}
ngOnInit() {
}
}
4.结果
formBuilder
将上个例子中的
constructor() {
this.myFormGroup = new FormGroup({
username:new FormControl(),
mobile:new FormControl(),
passwordGroup:new FormGroup({
pwd:new FormControl(),
pconfirm:new FormControl()
})
})
}
用 formBuilder 替换后
constructor(fb:FormBuilder) {
this.myFormGroup = fb.group({
username:[''],
mobile:[''],
passwordGroup:fb.group({
pwd:[''],
pconfirm:['']
})
})
}
最终的效果是一样的。
<4>表单校验
1、angular的校验器
校验器就是一个普通的方法,该方法接收一个参数,参数类型必须为AbstractControl,必须要有一个返回值,返回值可以是任意结构的一个对象,这个对象的key必须是string类型的。
例如:
xxxx(control:AbstractControl):{[key:string]:any} {
return null;
}
angular自带校验器例子:
import { Component, OnInit} from '@angular/core';
//引入
import { FormGroup,FormControl,FormBuilder,Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-rigist',
templateUrl: './reactive-rigist.component.html',
styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {
myFormGroup:FormGroup;
constructor(fb:FormBuilder) {
this.myFormGroup = fb.group({
// 第一个是默认值,第二个是校验器
// 单个校验器的写法
// username:['',[Validators.required,Validators.minLength(6)]],
// 多个校验器的写法
username:['',[Validators.required,Validators.minLength(6)]],
mobile:[''],
passwordGroup:fb.group({
pwd:[''],
pconfirm:['']
})
})
}
mySubmit(){
let isValid:boolean = this.myFormGroup.get("username").valid;
console.log("username的校验结果"+isValid);
let errors:any = this.myFormGroup.get("username").errors;
console.log("username的错误信息是"+JSON.stringify(errors));
console.log(this.myFormGroup.value);
}
ngOnInit() {
}
}
结果
2、自定义校验器
1.
import { Component, OnInit} from '@angular/core';
//引入
import { FormGroup,FormControl,FormBuilder,Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-rigist',
templateUrl: './reactive-rigist.component.html',
styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {
//自定义手机号校验器
mobileValidator(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 valid ? null : {mobile : true};
}
myFormGroup:FormGroup;
constructor(fb:FormBuilder) {
this.myFormGroup = fb.group({
username:['',[Validators.required,Validators.minLength(6)]],
//添加自定义的校验器
mobile:['',this.mobileValidator],
passwordGroup:fb.group({
pwd:[''],
pconfirm:['']
})
})
}
mySubmit(){
let isValid:boolean = this.myFormGroup.get("username").valid;
console.log("username的校验结果"+isValid);
let errors:any = this.myFormGroup.get("username").errors;
console.log("username的错误信息是"+JSON.stringify(errors));
console.log(this.myFormGroup.value);
}
ngOnInit() {
}
}
2、结果
3、为FormGroup自定义校验器
1、
import { Component, OnInit} from '@angular/core';
//引入
import { FormGroup,FormControl,FormBuilder,Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-rigist',
templateUrl: './reactive-rigist.component.html',
styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {
mobileValidator(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 valid ? null : {mobile : true};
}
//自定义方法
equalValidator(group:FormGroup):any {
let pwd:FormControl = group.get("pwd") as FormControl;
let pconfirm:FormControl = group.get("pconfirm") as FormControl;
let valid:boolean = (pwd.value === pconfirm.value);
console.log("密码校验结果:"+valid);
// 当校验通过时返回null,当校验不通过的时候返回{equal : true}
return valid ? null : {equal : true};
}
myFormGroup:FormGroup;
constructor(fb:FormBuilder) {
this.myFormGroup = fb.group({
username:['',[Validators.required,Validators.minLength(6)]],
mobile:['',this.mobileValidator],
passwordGroup:fb.group({
pwd:[''],
pconfirm:['']
// 加入声明,是一个对象
},{validator:this.equalValidator})
})
}
mySubmit(){
let isValid:boolean = this.myFormGroup.get("username").valid;
console.log("username的校验结果"+isValid);
let errors:any = this.myFormGroup.get("username").errors;
console.log("username的错误信息是"+JSON.stringify(errors));
console.log(this.myFormGroup.value);
}
ngOnInit() {
}
}
4、将校验器单独放到一个文件中,然后用export的方式暴露出去
·1.在app目录下新建一个文件夹
2.将刚刚定义的方法放置到validators.ts中
//引入文件
import { FormGroup,FormControl } from '@angular/forms';
// 注意:此时这两个不再是一个TypeScript方法了,而是全局的一个函数
// 要用function来声明
export function mobileValidator(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 valid ? null : {mobile : true};
}
export function equalValidator(group:FormGroup):any {
let pwd:FormControl = group.get("pwd") as FormControl;
let pconfirm:FormControl = group.get("pconfirm") as FormControl;
let valid:boolean = (pwd.value === pconfirm.value);
console.log("密码校验结果:"+valid);
// 当校验通过时返回null,当校验不通过的时候返回{equal : true}
return valid ? null : {equal : true};
}
3.在组件中引入这两个全局的方法
import { Component, OnInit} from '@angular/core';
import { FormGroup,FormControl,FormBuilder,Validators } from '@angular/forms';
//引入文件
import {mobileValidator,equalValidator} from '../validator/validators';
@Component({
selector: 'app-reactive-rigist',
templateUrl: './reactive-rigist.component.html',
styleUrls: ['./reactive-rigist.component.css']
})
export class ReactiveRigistComponent implements OnInit {
myFormGroup:FormGroup;
constructor(fb:FormBuilder) {
this.myFormGroup = fb.group({
username:['',[Validators.required,Validators.minLength(6)]],
//此次修改
mobile:['',mobileValidator],
passwordGroup:fb.group({
pwd:[''],
pconfirm:['']
// 此处修改
},{validator:equalValidator})
})
}
mySubmit(){
let isValid:boolean = this.myFormGroup.get("username").valid;
console.log("username的校验结果"+isValid);
let errors:any = this.myFormGroup.get("username").errors;
console.log("username的错误信息是"+JSON.stringify(errors));
console.log(this.myFormGroup.value);
}
ngOnInit() {
}
}
4.结果是相同的
5、用.myFormGroup的valid属性来判断整个表单中所有的值是否是合法的
1.修改代码
mySubmit(){
if(this.myFormGroup.valid) {
//只有合法时才打印模型信息
console.log(this.myFormGroup.value);
}else {
console.log("校验未通过");
}
}
2.结果
6、校验不通过时,显示错误信息给用户
1.修改模版
2.结果
7、在检验器中写错误信息
1.修改validators.ts
export function equalValidator(group:FormGroup):any {
let pwd:FormControl = group.get("pwd") as FormControl;
let pconfirm:FormControl = group.get("pconfirm") as FormControl;
let valid:boolean = (pwd.value === pconfirm.value);
console.log("密码校验结果:"+valid);
// return valid ? null : {myequal : true};
// 在此处添加错误信息
return valid ? null : {myequal : {errorInfo:"密码输入不一致"}};
}
2.修改模板
密码:
密码最少6位
确认密码:
{{myFormGroup.getError('myequal','passwordGroup')?.errorInfo}}
3.结果相同
8、异步校验器
将mobile检验器改为异步校验器
1.修改validators.ts
import{ Observable } from "rxjs";
// 异步校验器
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 : {mymobile : true}).delay(5000);
}
2.修改reactive-rigist.component.ts
mobile:['',mobileValidator,mobileAsyncValidator]
3.修改模版
添加
{{myFormGroup.status}}
4.结果
5秒后
<5>状态字段
包括:touched和untouched 、 pristine和dirty 、 pending
touched和untouched:
用来判断用户是否访问过这个字段,也就是这个字段是否获取过焦点。若获取过焦点,则touched是true,untouched 是false。
用户名:
用户名是必填项
用户名最小长度是6位
pristine和dirty
如果一个字段的值从来没被改变过,那么pristine为true,dirty为false。
请输入正确的手机号
pending
当一个字段正处于异步检验时,pending为true
正在校验手机号合法性
注意
针对所有的字段,angular会自动根据字段的状态来为它添加一些样式。
.myError {
border: 1px solid red;
}
用户名:
<6>模版式表单校验
1、生成两个指令
指令可以被看成是一个没有模版的component,指令是作为属性来用的。
ng g directive directives/moblieValidator
ng g directive directives/equalValidator