一梆掸、form中使用的input, select等均不建議使用ngModel綁定變量,因為Angular7會移除form中的這個指令,如果在6中使用則會報警告熟妓,直接使用formControl或者formControlName綁定form即可盯桦,如下
<form [formGroup]="targetForm" (ngSubmit)="save()" onkeypress="if(event.keyCode==13||event.which==13){return false;}">
<div>
<label>
姓名
</label>
<mat-form-field [floatLabel]="'never'">
<input matInput autocomplete="username" disableautocomplete type="text" name="username" formControlName="username" required>
</mat-form-field>
</div>
<div>
<button mat-button type="submit" class="sure">保存</button>
</div>
</form>
ts文件中targetForm定義如下:
targetForm
constructor(private fb: FormBuilder) {
this.targetForm = this.fb.group({
userName: ['王XX', Validators.required],
})
}
提交表單的時候慈俯,可以直接從剛剛定義的targetForm中取到value值,然后對應(yīng)提交
二拥峦、FormControl,FormGroup和FormArray
1贴膘、三者中FormControl屬于子元素,F(xiàn)ormGroup和FormArray可任意嵌套這三個元素
(1)FormGroup中嵌套FromControl略号。這是最常見的形式刑峡,上述示例中就是這種格式
(2)FormGroup中嵌套FormGroup洋闽。
這種格式一般是表單中某些項和某一項有關(guān)聯(lián)關(guān)系時使用,可以通過addControl來動態(tài)添加突梦,舉個栗子:
html
<form [formGroup]="targetForm" (ngSubmit)="save()" onkeypress="if(event.keyCode==13||event.which==13){return false;}">
<div>
<label>
職業(yè)
</label>
<mat-form-field [floatLabel]="'never'" class="dialog-input">
<mat-select placeholder="請選擇" formControlName="profession"
(selectionChange)="changeProfession($event)" required>
<mat-option *ngFor="let item of professions" [value]="item">
{{ item }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div *ngIf="targetForm.get('profession').value === 'teacher'" formGroupName="teacher">
<div>
<label>
學(xué)校
</label>
<mat-form-field [floatLabel]="'never'">
<input matInput autocomplete="school" disableautocomplete type="text" name="school" formControlName="school" required>
</mat-form-field>
</div>
<div>
<label>
年級
</label>
<mat-form-field [floatLabel]="'never'">
<input matInput autocomplete="grade" disableautocomplete type="text" name="grade" formControlName="grade" required>
</mat-form-field>
</div>
</div>
<div>
<button mat-button type="submit" class="sure">保存</button>
</div>
</form>
ts诫舅,當選擇職業(yè)為teacher時
constructor(private fb: FormBuilder){}
this.targetForm = fb.group({
profession: ['', Validators.required],
})
changeProfession(event) {
const {value} = event
if(value === 'teacher') {
const fbGroup = this.fb.group({
school: ['xxx', Validators.required],
grade: ['', Validators.required]
})
// contains方法判斷是否包含teacher control
if(!this.targetForm.contains('teacher')) {
this.targetForm.addControl('teacher', fbGroup)
}
} else{
// 刪除targetForm中的teacher control
this.targetForm.removeControl('teacher')
}
}
(3)FormGroup中嵌套FormArray,且FormArray中嵌套FormGroup阳似。一般用于對表單中數(shù)組的動態(tài)處理骚勘,舉個栗子:
html文件
<div>
<label>
職業(yè)
</label>
<mat-form-field [floatLabel]="'never'" class="dialog-input">
<mat-select placeholder="請選擇" formControlName="profession"
(selectionChange)="changeProfession($event)" required>
<mat-option *ngFor="let item of professions" [value]="item">
{{ item }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<ng-container *ngIf="targetForm.get('profession').value === 'teacher'">
<mat-icon style="color: #3CB371" (click)="addAction()">add</mat-icon>
<div formArrayName="testArr">
<ng-container *ngFor="let test of testArr.controls;let index = index" [formGroupName]="i">
<div class="col-5">
<mat-form-field class="w-100">
<mat-form-field class="w-100">
<input autocomplete="off" disableautocomplete matInput type="text" formControlName="key" placeholder="key">
</mat-form-field>
</mat-form-field>
</div>
<div class="col-5">
<mat-form-field class="w-100">
<input autocomplete="off" disableautocomplete matInput type="text" formControlName="value" placeholder="value">
</mat-form-field>
</div>
<div class="m-auto text-right">
<mat-icon style="color: #3CB371" class="cancelMatIcon" (click)="removeAction(index)">
delete
</mat-icon>
</div>
</ng-container >
</div>
</ng-container>
ts文件
constructor(private fb: FormBuilder){
this.targetForm = fb.group({
profession: ['', Validators.required],
testArr: fb.array([])
})
}
get testArr() {
return this.targetForm.get('testArr') as FormArray
}
// 新增
addAction() {
const fb = this.fb
const fbGroup = fb.group({
key: ['', Validators.required],
value: ['', Validators.required],
})
this.targetForm.controls.testArr.push(fbGroup)
}
// 刪除
removeAction(index) {
const arr = this.targetForm.get('testArr') as FormArray
arr.removeAt(index)
}
三、表單中常見的坑
表單中的input框回車就自動提交表單
解決方法撮奏,在<form>標簽上添加onkeypress="if(event.keyCode===13||event.which===13){return false;}"表單中的button標簽俏讹,如果不設(shè)置type,點擊默認觸發(fā)點擊事件畜吊,除了提交按鈕設(shè)置type='submit'泽疆,其他button需要設(shè)置type='button'屬性
formGroup里面嵌套formGroup,點擊提交的時候外層的能觸發(fā)驗證玲献,但是內(nèi)層的不能觸發(fā)驗證殉疼。解決方法:[formGroup] = "targetForm.controls['test']"改為formGroupName="test"
谷歌瀏覽器中,當input type=text與type=password相鄰時捌年,input框會自動填充用戶名瓢娜。解決方法為:設(shè)置兩個form將兩個input隔離開。如下:
<form>
<input type="text"/>
</form>
<form>
<input type="password"/>
</form>
- formGroup中嵌套的formArray,formArray中嵌套formGroup礼预,submit的時候眠砾,判斷this.targetForm.valid時,formArray內(nèi)部若不能校驗托酸,則需要查詢formArray用法是否有問題褒颈,需要設(shè)置formArrayName="testArr",且子元素需要設(shè)置formGroupName = 'i'励堡,形如上栗(3)谷丸;若formArray中是formControl,則子元素直接設(shè)置formControlName = 'i' 就可以了
6应结、開發(fā)項目時遇到一個問題刨疼,form中嵌套組件,組件中[formGroup]和父組件是同一個鹅龄,通過將父組件中的formGroup傳進去币狠,從而來實時變更form。組件中屬性是級聯(lián)關(guān)系且必填砾层,發(fā)現(xiàn)提交表單時子組件若未填寫漩绵,并沒有觸發(fā)表單驗證,通過嘗試發(fā)現(xiàn)可通過將formGroup中的子組件的formControl調(diào)用markAsTouched()方法來出發(fā)驗證肛炮。
7止吐、動態(tài)隱藏或新增表單中的某些必填formControl有時會造成新增后修改該屬性宝踪,值改了但是頁面沒有對應(yīng)更新。我們可以不刪除碍扔,隱藏時僅需設(shè)置這些屬性為非必填瘩燥,開放時設(shè)置為必填即可,設(shè)置代碼如下
addValidators(targetForm, attributes, validators) {
attributes.forEach(it => {
if (targetForm.get(it)) {
targetForm.get(it).setValidators(validators)
}
})
}
clearValidators(targetForm, attributes) {
attributes.forEach(it => {
if (targetForm.get(it)) {
targetForm.get(it).clearValidators()
targetForm.get(it).updateValueAndValidity({onlySelf: true})
}
})
}
8不同、表單中屬性設(shè)置disabled后厉膀,通過form.value將獲取不到該值,可通過form.getRawValue()獲取表單值
9二拐、切記組件中的input字段名不可和公用指令名重名服鹅,不然會同時作為指令作用在組件上,剛吃過這個虧emmm....