怎么結(jié)合使用FormArray和模態(tài)框?下面本篇文章給大家介紹一下Angular的FormArray和模態(tài)框結(jié)合使用的方法,希望對(duì)大家有所幫助!
業(yè)務(wù)場(chǎng)景
使用FormArray制作動(dòng)態(tài)表單。每創(chuàng)建一個(gè)表單,頁(yè)面就新增一個(gè)input顯示表單填寫(xiě)的標(biāo)題,點(diǎn)擊編輯再跳轉(zhuǎn)到點(diǎn)擊表單的填寫(xiě)內(nèi)容。【相關(guān)教程推薦:《angular教程》】
// 封裝獲取modelList get modelList() { return this.formGroup.get('modelList') as FormArray } constructor(private fb: FormBuilder) {} ngOnInit() { // 一開(kāi)始初始化arr為空數(shù)組 this.formGroup = this.fb.group({ // 內(nèi)部嵌套FormControl、FormArray、FormGroup modelList: this.fb.array([]) }) } // 模態(tài)框構(gòu)造內(nèi)部的表單 function newModel() { return this.fb.group({ modelName: [''], // 可以繼續(xù)嵌套下去,根據(jù)業(yè)務(wù)需求 }) } // 省略模態(tài)框部分代碼 // 傳遞到模態(tài)框的FormArray selectedType: FormArray
表單列表
表單詳情【模態(tài)框】
<form [FormGroup]="formGroup"> <div FormArrayName="modelList"> <ng-container *nfFor="let item of modelList.controls;let i = index" [FormGroupName]="i"> <nz-input-group [nzSuffix]="suffixIconSearch" > <input type="text" nz-input formControlName="modelName"/> </nz-input-group> <ng-template #suffixIconSearch> <span nz-icon nzType="edit" class="hover" (click)="showModal(i)" ></span> </ng-template> </ng-container> </div> </form> <nz-modal [(nzVisible)]="isVisible" nzTitle="Model" [nzFooter]="modalFooter" (nzOnCancel)="handleCancel()" (nzOnOk)="handleOk()" > <ng-container *nzModalContent> <form nz-form [formGroup]="selectedType"> <nz-form-item> <nz-form-label nzRequired>Model Test</nz-form-label> <nz-form-control> <input type="text" nz-input placeholder="請(qǐng)輸入ModelName" formControlName="modelName" /> </nz-form-control> </nz-form-item> <nz-form-item> <nz-form-control> <product-config></product-config> </nz-form-control> </nz-form-item> </form> </ng-container> <ng-template #modalFooter> <button *ngIf="!isNewModel" nzDanger nz-button nzType="default" (click)="handleDelete()">刪除</button> <button *ngIf="isNewModel" nz-button nzType="default" (click)="handleCancel()">取消</button> <button nz-button nzType="primary" (click)="handleOk()">保存</button> </ng-template> </nz-modal>
由于這種模態(tài)框比較特殊,割裂了表單的FormGroup之間的關(guān)系,在點(diǎn)擊的時(shí)候需要傳遞參數(shù)到模態(tài)框顯示部分值,如果單純傳遞參數(shù)使用this.modelList.at(index)
獲取實(shí)體到模態(tài)框上進(jìn)行賦值修改,在模態(tài)框點(diǎn)擊保存后會(huì)發(fā)現(xiàn)修改的值沒(méi)有在表單更新,而表單上對(duì)input值修改發(fā)現(xiàn)可以影響到模態(tài)框的內(nèi)容。
但是模態(tài)框新增的表單卻可以響應(yīng)到頁(yè)面中去。
原錯(cuò)誤代碼思路
-
點(diǎn)擊編輯后,將點(diǎn)擊的FormArray的元素傳遞給一個(gè)臨時(shí)變量
this.selectedType = <FormGroup>this.modelList.at(index);
,并且對(duì)模態(tài)框表單傳值。 -
模態(tài)框點(diǎn)擊保存再將原FormArray的值重新替換
this.modelList.removeAt(this.modelIndex) this.modelList.insert(this.modelIndex, this.selectedType)
-
點(diǎn)擊新增,創(chuàng)建一個(gè)新的FormGroup對(duì)象
-
保存添加push到原頁(yè)面的FormArray中
newModelType(): FormGroup { return this.fb.group({ modelName: ['', Validators.required], configList: this.fb.array([]), }); } // ...省略 // 模態(tài)框顯示 show() { this.isVisible = true this.selectedType = this.newModelType(); } // 保存 save() { this.isVisible = false // 原頁(yè)面FormArray this.modelList.push(this.selectedType); }
最后發(fā)現(xiàn)這種寫(xiě)法只能夠單向改變,頁(yè)面外input修改值會(huì)影響到模態(tài)框,但是模態(tài)框的值改變保存卻讓外部沒(méi)有更新。通過(guò)console方式查看頁(yè)面的FormArray內(nèi)部參數(shù)發(fā)現(xiàn)其實(shí)是有改變的,只是angular沒(méi)有檢測(cè)到。這個(gè)時(shí)候判斷沒(méi)有發(fā)生響應(yīng)的原因一般是沒(méi)有觸發(fā)angular檢測(cè)機(jī)制,仔細(xì)查看文檔發(fā)現(xiàn)有一行很重要 angular文檔在最下面寫(xiě)著
原本第一次閱讀的時(shí)候,覺(jué)得我遵守了這種原則,因?yàn)樵诰庉嫷臅r(shí)候,我選擇了操控原FormArray進(jìn)行元素刪除和插入,是遵循了這種規(guī)則,但是實(shí)際上在模態(tài)框賦值就已經(jīng)違反了這種原則,我在賦值的時(shí)候拿了FormArray的元素實(shí)例賦值給模態(tài)框的臨時(shí)變量,然后更改實(shí)例的值,又重新刪除插入,本質(zhì)上我操作的是同一個(gè)實(shí)例,所以angular沒(méi)有檢測(cè)到發(fā)生變化【雖然值發(fā)生改變】
所以正確的做法是啥??
在賦值的地方不能偷懶,仍然要重新創(chuàng)建新對(duì)象,再拿原對(duì)象的賦值?!鞠喈?dāng)于深拷貝】
this.selectedType = this.newModelType(); const old = this.modelList.at(index); this.selectedType.setValue({ 'modelName': old.get('modelName').value })
這時(shí)候就可以正常更新了。
總結(jié)
其實(shí)查到最后本質(zhì)上還是回歸文檔。在排查錯(cuò)誤也走了很多坑,而且國(guó)內(nèi)基本沒(méi)什么angular的文章,還得靠外網(wǎng)論壇去找問(wèn)題。