模板式表單校驗
- 在模板式表單中后臺沒有像響應(yīng)式的數(shù)據(jù)模型,指令是唯一能使用的東西,需要將校驗器方法包裝成指令,然后在模板中使用
- 在模板式表單中還可以使用angular默認已經(jīng)定義的校驗器required和minlength等,但是為了避免和HTML中的屬性發(fā)生沖突可以使用novalidate來關(guān)閉瀏覽器默認的表單校驗
<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>
- 模板式表單中由于組件里沒有可以編程控制的數(shù)據(jù)模型,所以如果想要在了解表單中的任何信息,都要從模板式將信息傳給組件控制器,在提交表單時,為了得知表單是否有效只能在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);
}
- 與響應(yīng)式表單相同使用hasError方法顯示錯誤信息,但是由于模板式表單并沒有formModel屬性,所以使用myForm.form來調(diào)用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>
- 通過狀態(tài)屬性來決定是否顯示,但是不能這樣myForm.form.get('username').valid||formModel.get('username').untouched直接獲取狀態(tài)屬性值
- 模板式表單和響應(yīng)式表單不同,它的模型的值和狀態(tài)的變更是異步的,而且很難控制,如果使用同步的方式去訪問這些屬性就會報錯,如果在模板式表單中訪問這些屬性,使用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;
}
}
表單處理實戰(zhàn)
- 需要實現(xiàn)的功能
處理商品搜索表單
在商品名稱中輸入時,提示最少輸入三個字
在商品價格中輸入負數(shù)時,提示商品價格不能為負數(shù)
商品類別中展示所以的商品類別
點擊搜索時,如果表單中有字段不合法時,控制中不打印任何數(shù)據(jù) - 往productService添加一個新的方法來獲取所有可用商品類別
getAllCategories():string[]{
return ["電子產(chǎn)品","硬件設(shè)備","圖書"];
}
- 使用響應(yīng)式表單完成效果
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)
}
}
}
}
- 建立一個表單的數(shù)據(jù)模型,將數(shù)據(jù)模型和模板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')">請輸入正數(shù)</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>