Angular中提供了模板驅(qū)動表單和響應(yīng)式表單。
相對來做,模板驅(qū)動表單使用更加簡單,只需要在表單外圍添加#myForm="ngForm"
指令,給每個(gè)表單項(xiàng)添加ngModel指令和name屬性,然后就可以通過myform.value獲取到表單中所有的值;
一、模板驅(qū)動表單
1、基礎(chǔ)用法
創(chuàng)建模板驅(qū)動表單需要3個(gè)步驟
1、添加#myForm="ngForm"
2、在每個(gè)input表單項(xiàng)上添加ngModel指令和name屬性
3、在app.module.ts中引入FormsModule
import { FormsModule } from '@angular/forms';
@NgModule(
{
imports:[FormsModule]
}
)
<form #myForm="ngForm">
<ion-item>
<ion-label>標(biāo)題:</ion-label>
<ion-input type="text" name="title" ngModel></ion-input>
</ion-item>
<ion-item>
<ion-label>子標(biāo)題:</ion-label>
<ion-input type="text" name="subtitle" ngModel></ion-input>
</ion-item>
</form>
{{myForm.value|json}}
//{{myForm.value.title|json}}取標(biāo)題的值
效果:

2、給每個(gè)表單項(xiàng)單獨(dú)定義數(shù)據(jù)模型
給每個(gè)input表單在name="title" ngModel基礎(chǔ)上,添加#mytitle="ngModel",把本表單數(shù)據(jù)綁定到mytitle數(shù)據(jù)模型上??梢酝ㄟ^{{mytitle.value}}直接獲取數(shù)據(jù)。
<form #myForm="ngForm">
<ion-item>
<ion-label>標(biāo)題:</ion-label>
<ion-input type="text" name="title" ngModel #mytitle="ngModel"></ion-input>
</ion-item>
<ion-item>
<ion-label>子標(biāo)題:</ion-label>
<ion-input type="text" name="subtitle" ngModel></ion-input>
</ion-item>
</form>
{{myForm.value|json}} <br>
{{mytitle.value}}

3、ngModelGroup使用
將需要?dú)w納到一個(gè)數(shù)據(jù)模型中的所有表單,放到一個(gè)ngModelGroup指令中去
<form #myForm="ngForm">
<ion-item>
<ion-label>標(biāo)題:</ion-label>
<ion-input type="text" name="title" ngModel></ion-input>
</ion-item>
<ion-item>
<ion-label>子標(biāo)題:</ion-label>
<ion-input type="text" name="subtitle" ngModel></ion-input>
</ion-item>
<div ngModelGroup="passwordInfo">
<ion-item>
<ion-label>密碼:</ion-label>
<ion-input type="text" name="password" ngModel></ion-input>
</ion-item>
<ion-item>
<ion-label>確認(rèn)密碼:</ion-label>
<ion-input type="text" name="password2" ngModel></ion-input>
</ion-item>
</div>
</form>
{{myForm.value|json}}

二、響應(yīng)式表單
1、創(chuàng)建
響應(yīng)式表單有三個(gè)表單類,F(xiàn)ormGroup、FormControl、FormArray,F(xiàn)ormGroup可以用來嵌套。ionic3中創(chuàng)建時(shí),不需要在app.module.ts中引入ReactiveFormModule。不需要在app.module中引用@angular/forms模塊,因?yàn)樵赼pp.module中已經(jīng)引入了@angular/platform-browser模塊,而在@angular/platform-browser模塊中又導(dǎo)出了 @angular/forms 。
<form [formGroup]="myform" (ngSubmit)="save()">
<ion-item>
<ion-label>標(biāo)題:</ion-label>
<ion-input type="text" name="title" formControlName="title"></ion-input>
</ion-item>
<div formArrayName="emails">
<ion-item *ngFor="let item of myform.get('emails').controls;let i=index;">
<ion-label>郵箱:</ion-label>
<ion-input type="text" [formControlName]="i"></ion-input>
</ion-item>
</div>
<div formGroupName="passwordInfo">
<ion-item>
<ion-label>密碼:</ion-label>
<ion-input type="text" formControlName="password1"></ion-input>
</ion-item>
<ion-item>
<ion-label>確認(rèn)密碼:</ion-label>
<ion-input type="text" formControlName="password2"></ion-input>
</ion-item>
</div>
<button ion-button type="submit" >保存</button>
</form>
import { FormGroup, FormControl, FormArray } from '@angular/forms';
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
@IonicPage(
{ name: "my" }
)
@Component({
selector: 'page-my',
templateUrl: 'my.html',
})
export class MyPage {
myform: FormGroup;
constructor(
public navCtrl: NavController,
public navParams: NavParams
) {
this.myform = new FormGroup({
title: new FormControl(),
emails: new FormArray([
new FormControl(),
new FormControl()
]),
passwordInfo: new FormGroup({
password1: new FormControl(),
password2: new FormControl()
})
});
}
save() {
console.log(this.myform.value);
}
}
效果:

2、使用FormBuilder簡化創(chuàng)建代碼
只需要修改my.ts中代碼
import { FormGroup, FormControl, FormArray, FormBuilder } from '@angular/forms';
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
@IonicPage(
{ name: "my" }
)
@Component({
selector: 'page-my',
templateUrl: 'my.html',
})
export class MyPage {
myform: FormGroup;
constructor(
public navCtrl: NavController,
public navParams: NavParams
) {
let fb: FormBuilder = new FormBuilder();
this.myform = fb.group({
title: [""],
emails: fb.array([
"", ""
]),
passwordInfo: fb.group({
password1: [""],
password2: [""]
})
});
}
save() {
console.log(this.myform.value);
}
}
三、響應(yīng)式表單的校驗(yàn)
在創(chuàng)建表單時(shí),推薦直接使用響應(yīng)式表單,因?yàn)樵谑褂肍ormBuilder創(chuàng)建表單模型的時(shí)候,可以直接提供本地校驗(yàn)和異步校驗(yàn)。
本地校驗(yàn)可以是系統(tǒng)自帶的一些校驗(yàn)(min、max、required、minLength、maxLength、requiredTrue、pattern、nullValidator),也可以是自定義校驗(yàn)器。
異步校驗(yàn)是返回一個(gè)流或者一個(gè)可觀察的promise對象。
下面例子戰(zhàn)士了本地校驗(yàn)的方法:
my.html代碼:
<ion-header>
<ion-navbar>
<ion-title>my</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-list>
<form [formGroup]="myform" (ngSubmit)="save()">
<ion-item>
<ion-label>標(biāo)題:</ion-label>
<ion-input type="text" name="title" formControlName="title"></ion-input>
</ion-item>
<ion-item>
<ion-label>手機(jī):</ion-label>
<ion-input type="text" name="mobile" formControlName="mobile"></ion-input>
</ion-item>
<div formArrayName="emails">
<ion-item *ngFor="let item of myform.get('emails').controls;let i=index;">
<ion-label>郵箱:</ion-label>
<ion-input type="text" [formControlName]="i"></ion-input>
</ion-item>
</div>
<div formGroupName="passwordInfo">
<ion-item>
<ion-label>密碼:</ion-label>
<ion-input type="text" formControlName="password1"></ion-input>
</ion-item>
<ion-item>
<ion-label>確認(rèn)密碼:</ion-label>
<ion-input type="text" formControlName="password2"></ion-input>
</ion-item>
</div>
<button ion-button type="submit">保存</button>
</form>
</ion-list>
</ion-content>
my.ts方法:
import { FormGroup, FormBuilder, Validators, FormControl, AbstractControl } from '@angular/forms';
import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
@IonicPage(
{ name: "my" }
)
@Component({
selector: 'page-my',
templateUrl: 'my.html',
})
export class MyPage {
myform: FormGroup;
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public fb: FormBuilder
) {
this.myform = this.fb.group({
title: ["", [Validators.required, Validators.minLength(3)]],
mobile: ["", [this.mobileValidator]],
emails: this.fb.array(["", ""]),
passwordInfo: this.fb.group({
password1: [""],
password2: [""]
}, { validator: this.passwordValidator })//子FormGroup數(shù)據(jù)校驗(yàn)必須是一個(gè){validator:***}形式的參數(shù)
});
}
//自定義校驗(yàn)器,參數(shù)必須是AbstractControl類型,此類型是FormControll、FormGroup、FormArray的父類。返回值是一個(gè)json,key必須是string類型。
// nameValidator(param: AbstractControl): { [key: string]: any } {
// return null;
// }
mobileValidator(mobile: FormControl): any {
let value = (mobile.value || "") + "";
let myreg = /^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}$/;
let valid = myreg.test(value);
return valid ? null : { mobile: true };
}
passwordValidator(passwordInfo: FormGroup): any {
let password1 = passwordInfo.get("password1").value;
let password2 = passwordInfo.get("password2").value;
let valid = (password1 == password2);
return valid ? null : { password: true };
}
save() {
let title = this.myform.get("title");
let mobile = this.myform.get("mobile");
let passwordInfo = this.myform.get("passwordInfo");
if (!this.myform.valid) {
if (title.hasError("required")) {
alert("標(biāo)題必填");
return;
}
//*******************注意hasError中參數(shù)必須都小寫********************
if (title.hasError("minlength")) {
alert("標(biāo)題最小3位");
return;
}
if (mobile.hasError("mobile")) {
alert("手機(jī)格式不對");
return
}
if (passwordInfo.hasError("password")) {
alert("兩次密碼輸入不一樣");
return
}
}
}
}
上面自定義了兩個(gè)校驗(yàn)器,mobileValidator和passwordValidator,可以對手機(jī)號碼和密碼進(jìn)行校驗(yàn)。
如果當(dāng)myform.vlide==true,則說明整個(gè)表單模型沒有錯(cuò)誤。
要獲取某一個(gè)表單控件的校驗(yàn)信息:this.myform.get("title").errors
獲取某一個(gè)表單控件某一種校驗(yàn)是否通過:this.myform.get("title").hasError("minlength")。注意這里的參數(shù)一般是小寫,可以答應(yīng)errors結(jié)果看下,參數(shù)就是里面的key的值。
大型項(xiàng)目一般不會把自定義校驗(yàn)放在具體頁面里面,而是建立一個(gè)校驗(yàn)ts文件,這些校驗(yàn)函數(shù)都放在校驗(yàn)文件里面。新建一個(gè)validators.ts,注意當(dāng)把類中方法改成獨(dú)立函數(shù)的時(shí)候,需要在前面加上function,如果是公共函數(shù),則要加上export function。
validators.ts文件
import { FormGroup, FormControl } from '@angular/forms';
export function mobileValidator(mobile: FormControl): any {
let value = (mobile.value || "") + "";
let myreg = /^((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}$/;
let valid = myreg.test(value);
return valid ? null : { mobile: true };
}
export function passwordValidator(passwordInfo: FormGroup): any {
let password1 = passwordInfo.get("password1").value;
let password2 = passwordInfo.get("password2").value;
let valid = (password1 == password2);
return valid ? null : { password: true };
}
my.ts文件修改:
import { mobileValidator, passwordValidator } from '../validators'//**************頭部需要引用*************
constructor(
......
) {
this.myform = this.fb.group({
title: ["", [Validators.required, Validators.minLength(3)]],
mobile: ["", [mobileValidator]],//***********直接寫函數(shù)名稱**********
emails: this.fb.array(["", ""]),
passwordInfo: this.fb.group({
password1: [""],
password2: [""]
}, { validator: passwordValidator })//***********直接寫函數(shù)名稱**********
});
}
四、響應(yīng)式編程
1、簡單的響應(yīng)式編程
當(dāng)我們使用ngModel綁定數(shù)據(jù)模型時(shí),就已經(jīng)實(shí)現(xiàn)了簡單的響應(yīng)式編程。
html模板代碼
<ion-input type="text" [(ngModel)]="title"></ion-input>
{{title}}
當(dāng)在輸入框輸入文字時(shí),頁面上會動態(tài)輸出文字內(nèi)容。
2、數(shù)據(jù)流響應(yīng)式編程
使用ngModel方式綁定的數(shù)據(jù)模型,每次keyup都會直接把數(shù)據(jù)輸出。假如我們需要每次輸入500ms后才輸出,這時(shí)候就需要把輸入這個(gè)事件流做好監(jiān)聽。
html模板代碼:
<ion-input type="text" name="title2" [formControl]="title2"></ion-input>
ts文件:
import "rxjs";
title2: FormControl = new FormControl();
constructor(){
this.title2.valueChanges
.debounceTime(500)
.subscribe(
(data) => {
console.log(data);
}
)
}
angular教程說需要在app.module.ts中引入ReactiveFormsModule,但是在ionic3實(shí)際使用中,不加ReactiveFormsModule也可以正常運(yùn)行。