You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 11:38:11