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

Angular动态响应式表单可构建但控件无法编辑问题求助

Angular动态响应式表单无法编辑的解决方案

问题描述

已通过代码构建出Angular动态响应式表单字段,但所有表单控件无法进行编辑操作。

原组件代码

export class BillerDetailsConfirmComponent implements OnInit {
  billerForm!: FormGroup;

  constructor(
    private router: Router,
    private dialogService: NbDialogService,
    private fb: FormBuilder,
    private dashboardService: DashboardService,
    private subScriptionService: SubscriptionService,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit(): void {
    this.initializeForm();
    this.getCompleteBillerDetails();
  }

  initializeForm(): void {
    this.billerForm = this.fb.group({
      billerDetails: this.fb.array([])
    });
  }

  getCompleteBillerDetails(): void {
    const billersSubscription = this.dashboardService.getAllBBPSBillers().subscribe(
      (respData: any) => {
        if (respData.respCode === '00') {
          console.log('API Response:', respData.response);
          this.populateFormArray(this.billerDetails, respData.response.billerDetails);
         
        }
      },
      (error: any) => {
        console.error('Error fetching biller details:', error);
      }
    );
    this.cdr.detectChanges(); 

    this.subScriptionService.add("billerCategorySubscription", billersSubscription);
  }

  populateFormArray(formArray: FormArray, data: any[]): void {
    formArray.clear();
    data.forEach(item => {
      const formGroup = this.createFormGroup(item);
      formArray.push(formGroup);
    });
    console.log('Form Array:', formArray);
  }

  createFormGroup(item: any): FormGroup {
    const formGroup: { [key: string]: FormControl } = {};

    Object.entries(item).forEach(([key, value]) => {
      if (typeof value !== 'object') {
        formGroup[key] = new FormControl(value ?? ''); // Ensure controls are created and enabled.
      }
    });

    return this.fb.group(formGroup);
  }

  get billerDetails(): FormArray {
    return this.billerForm.get('billerDetails') as FormArray;
  }


  getFormControlKeys(group: AbstractControl): string[] {
    if (group instanceof FormGroup) {
      return Object.keys(group.controls).filter(key =>
        group.get(key) instanceof FormControl
      );
    }
    return [];
  }

  getFieldChunks(keys: string[], size: number): string[][] {
    const result = [];
    for (let i = 0; i < keys.length; i += size) {
      result.push(keys.slice(i, i + size));
    }
    return result;
  }
}

原视图代码

<nb-tab tabTitle="Biller Details">
  <div class="block-body">
    <form [formGroup]="billerForm">
      <div *ngFor="let billerGroup of billerDetails.controls; let i = index" [formGroup]="billerGroup">
        <ng-container *ngIf="billerGroup?.controls">
          <ng-container *ngFor="let chunk of getFieldChunks(getFormControlKeys(billerGroup), 3)">
            <div class="row mb-4 justify-content-start">
              <div class="col-md-4 d-flex flex-column" *ngFor="let key of chunk">
                <label class="form-label">{{ key | titlecase }}</label>
                <input nbInput class="w-100" [formControlName]="key" placeholder="Enter {{ key }}" fieldSize="large" />
              </div>
            </div>
          </ng-container>
        </ng-container>
      </div>
    </form>
  </div>
</nb-tab>

修复后的组件代码

export class BillerDetailsConfirmComponent implements OnInit {
  billerForm!: FormGroup;
  billerFieldChunks: any[] = []; // 新增:缓存字段分块数据

  constructor(
    private router: Router,
    private dialogService: NbDialogService,
    private fb: FormBuilder,
    private dashboardService: DashboardService,
    private subScriptionService: SubscriptionService,
    private cdr: ChangeDetectorRef
  ) {}

  ngOnInit(): void {
    this.initializeForm();
    this.getCompleteBillerDetails();
  }

  initializeForm(): void {
    this.billerForm = this.fb.group({
      billerDetails: this.fb.array([])
    });
  }

  getCompleteBillerDetails(): void {
    const billersSubscription = this.dashboardService.getAllBBPSBillers().subscribe(
      (respData: any) => {
        if (respData.respCode === '00') {
          console.log('API Response:', respData.response);
          this.populateFormArray(this.billerDetails, respData.response.billerDetails);
          this.cdr.detectChanges(); // 移至回调内,确保数据更新后触发变更检测
        }
      },
      (error: any) => {
        console.error('Error fetching biller details:', error);
      }
    );
    this.subScriptionService.add("billerCategorySubscription", billersSubscription);
  }

  populateFormArray(formArray: FormArray, data: any[]): void {
    formArray.clear();
    this.billerFieldChunks = [];
    data.forEach(item => {
      const formGroup = this.createFormGroup(item);
      formArray.push(formGroup);
      // 缓存当前FormGroup的字段分块
      const keys = this.getFormControlKeys(formGroup);
      this.billerFieldChunks.push(this.getFieldChunks(keys, 3));
    });
    console.log('Form Array:', formArray);
  }

  createFormGroup(item: any): FormGroup {
    const formGroup: { [key: string]: any } = {};

    Object.entries(item).forEach(([key, value]) => {
      if (typeof value !== 'object') {
        // 用FormBuilder创建控件,显式确保控件启用
        formGroup[key] = this.fb.control(value ?? '', { disabled: false });
      }
    });

    return this.fb.group(formGroup);
  }

  get billerDetails(): FormArray {
    return this.billerForm.get('billerDetails') as FormArray;
  }

  getFormControlKeys(group: AbstractControl): string[] {
    if (group instanceof FormGroup) {
      return Object.keys(group.controls).filter(key =>
        group.get(key) instanceof FormControl
      );
    }
    return [];
  }

  getFieldChunks(keys: string[], size: number): string[][] {
    const result = [];
    for (let i = 0; i < keys.length; i += size) {
      result.push(keys.slice(i, i + size));
    }
    return result;
  }
}

修复后的视图代码

<nb-tab tabTitle="Biller Details">
  <div class="block-body">
    <form [formGroup]="billerForm">
      <div *ngFor="let billerGroup of billerDetails.controls; let i = index" [formGroup]="billerGroup">
        <ng-container *ngIf="billerFieldChunks[i]">
          <ng-container *ngFor="let chunk of billerFieldChunks[i]">
            <div class="row mb-4 justify-content-start">
              <div class="col-md-4 d-flex flex-column" *ngFor="let key of chunk">
                <label class="form-label">{{ key | titlecase }}</label>
                <input nbInput class="w-100" [formControlName]="key" placeholder="Enter {{ key }}" fieldSize="large" />
              </div>
            </div>
          </ng-container>
        </ng-container>
      </div>
    </form>
  </div>
</nb-tab>

关键修复点说明

  1. 调整变更检测时机:将cdr.detectChanges()移至API响应的成功回调内,确保表单数据填充完成后再触发视图更新,避免控件绑定失效。
  2. 确保控件可编辑状态:改用FormBuilder创建控件,并显式设置{ disabled: false },消除异步加载可能导致的控件禁用问题。
  3. 缓存模板计算数据:新增billerFieldChunks数组缓存字段分块结果,避免模板中频繁调用方法引发的性能问题与视图不稳定。

内容的提问来源于stack exchange,提问作者vishnu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 22:26:04