Angular响应式表单:FormArray切换FormGroup时模态框显示旧数据
Angular响应式表单模态框切换FormArray项数据不更新问题
问题描述
使用Angular响应式表单模块绑定名为days的FormArray中的多个FormGroup,通过Material拖拽组件循环展示这些项。点击循环项的按钮时,Bootstrap模态框应展示对应日期的详情,但首次点击正常,切换到另一项时,模态框仍显示前一次点击的数据。
已在模板中正确配置FormGroup、formArrayName、formGroupName和formControlName属性。
相关代码
模态框HTML代码
<form class="modal-body" [formGroup]="WorkoutForm"> <div class="day-form" formArrayName="days"> <div *ngIf="this.selectedFitnessDayIndex >= 0" class="specific-day-form" [formGroupName]="selectedFitnessDayIndex"> <div *ngIf="!editWorkoutToggled"> <div class="workoutheaderbuttons"> <button style="margin-right: 1em;" *ngIf="!this.requestProposal" (click)="saveFitnessDayLoadout(selectedFitnessDayIndex)" class="savedaybutton btn btn-secondary" type="button" name="button">Save Day <br> loadout</button> <button *ngIf="!this.requestProposal" (click)="toggleLoadFitnessDay(selectedFitnessDayIndex)" class="loaddaybutton btn btn-secondary" type="button" name="button">Load day <br>loadout</button> </div> <h5 [ngClass]="{'saveDayFaulty': this.WorkoutForm.value.days[selectedFitnessDayIndex].saveDayMessage !== 'Succesfully saved this fitness day as a loadout', 'saveDaySuccesful': this.WorkoutForm.value.days[selectedFitnessDayIndex].saveDayMessage == 'Succesfully saved this fitness day as a loadout'}" style="padding-top: .6em;width: 80%;text-align: center;margin-left: auto;margin-right: auto;">{{this.WorkoutForm.value.days[selectedFitnessDayIndex].saveDayMessage}}</h5> <p *ngIf="this.WorkoutForm.value.days[selectedFitnessDayIndex].loadDayToggled && this.savedFitnessDays.length == 0">You have no saved fitness day loadouts</p> <div *ngIf="this.WorkoutForm.value.days[selectedFitnessDayIndex].loadDayToggled && this.savedFitnessDays.length > 0" class="loaddayparent"> <p>Select Fitness Day to Load: *</p> <div class="dayoptions"> <div *ngFor="let option of this.savedFitnessDays;let optionIndex=index;" class="dayOption"> <h5 (click)="selectFitnessDayLoadout(option._id, selectedFitnessDayIndex)">{{option.name}}</h5> </div> </div> </div> <label for="">Change Day Name: </label> <p>selected day index: {{selectedFitnessDayIndex}}</p> <h3>Day value : {{ WorkoutForm.days[selectedFitnessDayIndex].dayName}}</h3> <input type="text" class="form-control" formControlName="dayName"> <label for="">Rest Days after This Day: </label> <input [readonly]="this.requestProposal" class="form-control" formControlName="restdaysAfter" type="number" name="" value=""> </div> </div> </div> </form>
组件TS代码(打开模态框方法)
openDayModal(dayIndex: number){ this.selectedFitnessDay = this.getDays().value.at(dayIndex); this.selectedFitnessDayIndex = dayIndex; console.log('this day:', this.getDays().at(dayIndex).value); console.log("SELECTED INDEX", this.selectedFitnessDayIndex); }
模板调用代码
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)"> @for (day of getDays().controls; track day; let dayIndex = $index;) { <div class="example-box" cdkDrag> <div class="example-custom-placeholder" *cdkDragPlaceholder></div> <p>{{day.value.dayName}}</p> <p (click)="openDayModal(dayIndex)" data-bs-toggle="modal" data-bs-target="#fitnessDayModal" class="edit-day">Edit <i class="bi bi-pencil-square"></i></p> </div> } </div>
解决方案
核心原因
Bootstrap模态框首次打开后会缓存DOM结构,原生data-bs-toggle触发方式下,Angular变更检测无法及时关联新的formGroupName,导致表单控件仍绑定旧的FormGroup。
具体修复步骤
1. 手动控制模态框生命周期
移除模板中的data-bs-toggle和data-bs-target,改用Angular代码控制模态框:
- 引入Bootstrap Modal类并初始化:
import { Modal } from 'bootstrap'; import { ChangeDetectorRef, Component, NgAfterViewInit } from '@angular/core'; @Component({ // 组件元数据 }) export class YourComponent implements NgAfterViewInit { private fitnessDayModal?: Modal; constructor(private changeDetectorRef: ChangeDetectorRef) {} ngAfterViewInit(): void { const modalEl = document.getElementById('fitnessDayModal'); if (modalEl) { this.fitnessDayModal = new Modal(modalEl); } } }
- 修改
openDayModal方法:
openDayModal(dayIndex: number){ this.selectedFitnessDayIndex = dayIndex; // 强制触发变更检测,确保表单重新绑定到正确的FormGroup this.changeDetectorRef.detectChanges(); // 手动打开模态框 this.fitnessDayModal?.show(); }
- 更新模板按钮:
<p (click)="openDayModal(dayIndex)" class="edit-day">Edit <i class="bi bi-pencil-square"></i></p>
2. 优化表单取值逻辑
避免直接从WorkoutForm.value取值,改用表单控件的get方法获取最新值,比如:
将{{this.WorkoutForm.value.days[selectedFitnessDayIndex].saveDayMessage}}替换为:
{{ getDays().at(selectedFitnessDayIndex)?.get('saveDayMessage')?.value || '' }}
确保getDays()方法返回最新的FormArray:
getDays(): FormArray { return this.WorkoutForm.get('days') as FormArray; }
3. 验证拖拽后的索引正确性
拖拽操作会改变FormArray中控件的顺序,确保dayIndex始终对应当前控件的正确位置,可在drop方法中打印getDays().controls确认顺序是否正确。
内容的提问来源于stack exchange,提问作者L.J.R.
相关产品推荐
相关产品推荐

