模板式表单校验
- 在模板式表单中后台没有像响应式的数据模型,指令是唯一能使用的东西,需要将校验器方法包装成指令,然后在模板中使用
- 在模板式表单中还可以使用angular默认已经定义的校验器required和minlength等,但是为了避免和HTML中的属性发生冲突可以使用novalidate来关闭浏览器默认的表单校验
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value)" novalidate>
<div>手机号:<input ngModel required name="mobile" type="number"></div>
<button type="submit">注册</button>
</form>
- 使用ng命令生成一个指令
ng g directive directives/mobileValidator
- 指令 就是一个没有模板的组件,组件作为标签来使用,指令可以作为HTML的属性来使用
- 将之前写的校验方法包装到指令中去,在装饰器中写一个providers提供器,校验器的包装指令的token是固定的NG_VALIDATORS
- 将校验手机号的方法包装成指令
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() { }
}
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value)" novalidate>
<div>用户名:<input ngModel required minlength="6" name="username" type="text"></div>
<div>手机号:<input ngModel mobile name="mobile" type="number"></div>
<div ngModelGroup="passwordsGroup" equal>
<div>密码:<input ngModel minlength="6" name="password" type="password"></div>
<div>确认密码:<input ngModel name="pconfirm" type="password"></div>
</div>
<button type="submit">注册</button>
</form>
- 模板式表单中由于组件里没有可以编程控制的数据模型,所以如果想要在了解表单中的任何信息,都要从模板式将信息传给组件控制器,在提交表单时,为了得知表单是否有效只能在onSubmit方法中传入
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value,myForm.valid)" novalidate>
<button type="submit">注册</button>
</form>
onSubmit(value:any,valid:boolean){
console.log(valid);
console.log(value);
}
- 与响应式表单相同使用hasError方法显示错误信息,但是由于模板式表单并没有formModel属性,所以使用myForm.form来调用hasError方法,
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value,myForm.valid)" novalidate>
<div>用户名:<input ngModel required minlength="6" name="username" type="text"></div>
<div [hidden]="myForm.form.get('username').valid || formModel.get('username').untouched">
<div [hidden]="!myForm.form.hasError('required','username')">
用户名是必填项
</div>
<div [hidden]="!myForm.form.hasError('minlength','username')">
用户最小长度为6
</div>
</div>
<div>手机号:<input ngModel mobile name="mobile" type="number"></div>
<div [hidden]="!myForm.form.hasError('mobile','mobile')||formModel.get('mobile').untouched">
请输入正确的mobile
</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>
<div [hidden]="!myForm.form.hasError('equal','passwordsGroup')">
{{myForm.form.getError('equal','passwordsGroup')?.descxx}}
</div>
<button type="submit">注册</button>
</form>
- 通过状态属性来决定是否显示,但是不能这样myForm.form.get('username').valid||formModel.get('username').untouched直接获取状态属性值
- 模板式表单和响应式表单不同,它的模型的值和状态的变更是异步的,而且很难控制,如果使用同步的方式去访问这些属性就会报错,如果在模板式表单中访问这些属性,使用input属性绑定
<form #myForm="ngForm" (ngSubmit)="onSubmit(myForm.value,myForm.valid)" novalidate>
<div>用户名:<input ngModel required minlength="6" name="username" (input)="onMobileInput(myForm)" type="text"></div>
<div [hidden]="mobileValid||mobileUntouched">
<div [hidden]="!myForm.form.hasError('required','username')">
用户名是必填项
</div>
<div [hidden]="!myForm.form.hasError('minlength','username')">
用户最小长度为6
</div>
</div>
</div>
<button type="submit">注册</button>
</form>
mobileValid:boolean=true;
mobileUntouched=true;
onMobileInput(form: NgForm) {
if(form){
this.mobileValid=form.form.get("mobile").valid;
this.mobileUntouched=form.form.get("mobile").untouched;
}
}
表单处理实战
- 需要实现的功能
处理商品搜索表单
在商品名称中输入时,提示最少输入三个字
在商品价格中输入负数时,提示商品价格不能为负数
商品类别中展示所以的商品类别
点击搜索时,如果表单中有字段不合法时,控制中不打印任何数据 - 往productService添加一个新的方法来获取所有可用商品类别
getAllCategories():string[]{
return ["电子产品","硬件设备","图书"];
}
- 使用响应式表单完成效果
export class SearchComponent implements OnInit {
formModel: FormGroup;
categories: string[];
constructor(private productService:ProductService) {
let fb=new FormBuilder();
this.formModel=fb.group({
title:['',Validators.minLength(3)],
price:[null,this.positiveNumberValidator],
category:['-1']
})
}
ngOnInit() {
this.categories=this.productService.getAllCategories();
}
positiveNumberValidator(control: FormControl): any {
let value = control.value;
if (!value) {
return null;
}
let price = parseInt(value);
if (price > 0) {
return null;
} else {
return { positiveNumber: true }
}
}
onSubmit(): void {
if (this.formModel.valid) {
console.log(this.formModel.value)
}
}
}
}
- 建立一个表单的数据模型,将数据模型和模板HTML元素连接起来
<form [formGroup]="formModel" (ngSubmit) = "onSubmit()" novalidate>
<div class="form-group" [class.has-error]="formModel.hasError('minlength','title')">
<label for="productTitle">商品名称:</label>
<input type="text" formControlName="title" id="productTitle" class="form-control" placeholder="商品名称">
<span class="help-block" [class.hidden]="!formModel.hasError('minlength','title')">请至少输入三个字符</span>
</div>
<div class="form-group" [class.has-error]="formModel.hasError('positiveNumber','price')">
<label for="productPrice">商品价格:</label>
<input type="text" formControlName="price" id="productPrice" name="productPrice" class="form-control" placeholder="商品价格">
<span class="help-block" [class.hidden]="!formModel.hasError('positiveNumber','price')">请输入正数</span>
</div>
<div class="form-group">
<label for="productCategory">商品类别:</label>
<select formControlName="category" class="form-control" id="productCategory">
<option value="-1">--全部分类--</option>
<option *ngFor="let category of categories" [value]="category">{{category}}</option>
</select>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">
搜索
</button>
</div>
</form>