时隔十多天我(独臂侠 灰常怀念两只胳膊~~(><)~~)又来了,之前是第三章的内容,今天先写*第七章表单处理*的内容吧,内容太多了,有必要记下来,如果有幸被看到欢迎指正^^
表单有:
- 模板式表单
- 响应式表单
模版式适合简单的场景, 响应式表单适合复杂的场景,如果不想让angular处理你的表单需要添加ngNoForm属性,如果不想让浏览器处理,则需要添加novalidate
模板式表单,及其校验
在指定了ngform指令的表单里,ngmodel是不需要[] 或()的,但必须指定name属性,下面这个代码片段是最终的模板式表单,
<form action="/regist" method="post" #myForm = "ngForm" (ngSubmit) = "onSubmit(myForm.value, myForm.valid)" novalidate>
<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>
<div>手机号:<input ngModel mobile name = "mobile" type="number"></div>
<div [hidden] = "!myForm.form.hasError('mobile', 'mobile')">请输入正确的手机号aaafffaa</div>
<div ngModelGroup="passwordsGroup" equal>
<div>密码:<input ngModel minlength="6" name="password" type="password"></div>
<div [hidden] = "!myForm.form.hasError('minlength', ['passwordsGroup', 'password'])">密码最小长度是6</div>
<div>确认密码:<input ngModel name="pconfirm" type="password"></div>
<div [hidden] = "!myForm.form.hasError('equal', 'passwordsGroup')">
{{myForm.form.getError('equal', 'passwordsGroup')?.descs}}
</div>
</div>
<button type="submit">注册</button>
</form>
onSubmit(value: any, valid: boolean) {
console.log(valid);
console.log(value);
}
mobileValid: boolean = true;
mobileUntouched: boolean = true;
onMobileInput(form: NgForm) {
if ( form ) {
this.mobileValid = form.form.get('username').valid;
this.mobileUntouched = form.form.get('username').untouched;
console.log(this.mobileValid + '----------------------' + this.mobileUntouched);
}
}
equal,mobile这些指令是在一个单独的文件中写
创建指令,directives是单独的文件夹
ng g directive directives/mobileValidator
ng g directive directives/equalValidator
mobileValidator.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() { }
}
equalValidator.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() { }
}
这里要注意的就是providers 记得添加这个,还要注入validators里的校验方法,这个在下面写响应式表单的时候贴出来
下面解释代码的意思
(ngSubmit) = "onSubmit(myForm.value, myForm.valid)"
这行代码是在表单提交的时候把整个表单的信息,合法性传递给这个方法,用来处理表单,本例是在控制台打印出表单的信息和合法性
onSubmit(value: any, valid: boolean) {
console.log(valid);
console.log(value);
}
angular有针对表单的预定义的校验器Required ,minlength,maxlength,pattern(正则) …
required minlength="6"
<div>用户名:<input ngModel required minlength="6" name="username" type="text" (input)="onMobileInput(myForm)"></div>
这段代码是为用户名的input绑定一个方法,传入myForm,记得要传入 不然没办法获取表单信息,在此获取的是这个输入框的valid,untouched属性
mobileValid: boolean = true;
mobileUntouched: boolean = true;
onMobileInput(form: NgForm) {
if ( form ) {
this.mobileValid = form.form.get('username').valid;
this.mobileUntouched = form.form.get('username').untouched;
console.log(this.mobileValid + '----------------------' + this.mobileUntouched);
}
}
响应式表单及其校验
FormGroup是多个FormControl的集合,若有一个formcontrol无效 则整个formgroup无效,FormArray 与FormGroup类似,但他有一个长度属性,他是一个可以增长的字段集合
FormGroup是固定的,如一个邮箱输入,用户不止一个邮箱,用formarray可以输入多个邮箱
第二列是属性绑定,用属性绑定语法即[]语法,formarray不能通过属性来绑定
FormControl不能用在formgroup里,在formGroup里要用formcontrolname
<form [formGroup]="formModel" (submit)="onSubmit()">
<div>用户名:<input[class.hasError]="formModel.get('username').invalid && formModel.get('username').touched" type="text" formControlName="username"></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>手机号<input type="text" formControlName="mobile"></div>
<div [hidden] = "formModel.get('mobile').valid || formModel.get('mobile').pristine">
<div [hidden] = "!formModel.hasError('mobile', 'mobile')">请输入正确的手机号</div>
</div>
<div [hidden] = "!formModel.get('mobile').pending">
正在校验手机号合法性
</div>
<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}}
</div>
</div>
<button type="submit">注册</button>
</form>
<div>
{{formModel.status}}
</div>
import { Component, OnInit } from '@angular/core';
import {AbstractControl, FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
import {equalValidator, mobileAsyncValidator, mobileValidator} from '../validator/validators';
import {validate} from "codelyzer/walkerFactory/walkerFn";
@Component({
selector: 'app-reactive-regist',
templateUrl: './reactive-regist.component.html',
styleUrls: ['./reactive-regist.component.css']
})
export class ReactiveRegistComponent implements OnInit {
formModel: FormGroup;
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})
});
}
onSubmit() {
let isValid: boolean = this.formModel.get("mobile").valid;
console.log("mobile的检验结果" + isValid);
let errors: any = this.formModel.get("mobile").errors;
console.log("mobile的错误信息是" + JSON.stringify(errors));
if (this.formModel.value) {
console.log(this.formModel.value);
}
}
ngOnInit() {
}
}
validator.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 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);
}
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: "两次密码不一致"} };
}
<div>用户名<input[class.hasError]="formModel.get('username').invalid && formModel.get('username').touched" type="text" formControlName="username"></div>
这段代码动态地为input添加了样式 只有在后面表达式为真时才显示样式,需要注意的是输入密码和确认密码这里
<div [hidden] = "!formModel.hasError('minlength', ['passwordsGroup', 'password'])">密码最小长度是6</div>
export class ReactiveRegistComponent implements OnInit {
formModel: FormGroup;
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})
});
// this.formModel = new FormGroup({
// username: new FormControl(),
// mobile: new FormControl(),
// passwordsGroup: new FormGroup({
// password: new FormControl(),
// pconfirm: new FormControl()
// })
// });
}
后面注释的部分是另外一种写法 可以加参数,表示的是初始值
username: new FormControl("aaa"),
username: ['aaa', [Validators.required, Validators.minLength(6)]],
第一个方法里面需要注入FormBuilder,他的第一个参数表示初始值,第二个参数是校验器,可以有多个校验器写成数组的形式,第三个参数是异步校验器
最后看一下
表单的状态字段
Touched untouched 表示用户是否获取过字段
字段被修改过 dirty是true pristine是false
字段正处于异步校验时pending为true