动态 FormControl 值在 Angular 中绑定不正确的问题

问题描述 投票:0回答:1

编辑:这是我的 Stackblitz 应用程序的 编辑器 url,它以简化的设置显示了第一个控件和第二个控件之间的值“转移”问题。

我正在 Angular 中开发动态表单,其中表单结构根据用户输入而变化。表单中的每个问题都由 FormGroup 中的唯一控件表示,并且当用户浏览问题时动态创建或更新控件。我的方法包括更新 currentControlName 并在导航上重新创建表单控件(使用 nextPage 和 prevPage 方法),以确保每个问题在表单中都有自己独特的控件。

方法:

我使用一项服务来根据所选服务获取问题。 该表单在 ngOnInit 中初始化,第一个问题作为当前问题。 在问题之间导航时,我为每个问题创建一个新的 FormControl,并使用问题 ID 通过唯一名称进行标识。 我将答案存储在一个对象中,以便即使在问题之间来回导航时也能保留答案。

问题:

输入第一个问题的答案并导航到第二个问题后,第二个问题的输入字段错误地显示为第一个问题输入的值。此外,更新第二个问题的值不会触发预期的 valueChanges observable,并且表单控件和模板之间似乎存在不匹配或绑定问题。

具体:

第一个输入控件按预期工作,记录值变化。 导航到第二个问题并更新其控件后,没有记录任何更改,这表明可能无法为新创建的控件正确设置可观察对象。 尽管在每个导航上重新创建了表单组和控件,但模板中控件值的绑定似乎始终存在问题。

尝试解决:

根据问题 ID 确保每个 FormControl 的名称唯一。 使用 valueChanges observable 来记录和跟踪控制值的变化。 在每次导航时重新创建 FormGroup 及其控件,以尝试重置表单状态。

我正在寻找见解或解决方案,以确保每个动态创建的控件正确反映其在模板中的值,并准确检测和记录值更改。任何关于如何解决绑定问题或改进 Angular 中的动态表单处理的建议将不胜感激。

Angular CLI:14.2.4 节点:21.6.1

编辑:用极简代码重现我的问题

最小.组件.ts

import { FormBuilder, FormGroup, Validators } from '@angular/forms';

interface Question {
  id: string;
  label: string;
}

@Component({
  selector: 'app-minimal-form',
  templateUrl: './minimal.component.html',
})
export class MinimalFormComponent implements OnInit {
  myForm: FormGroup;
  currentQuestion: Question;
  questions: Question[] = [
    { id: 'A', label: 'Question A' },
    { id: 'B', label: 'Question B' },
  ];
  currentControlName: string;

  constructor(private fb: FormBuilder) {}

  ngOnInit(): void {
    this.currentQuestion = this.questions[0];
    this.currentControlName = `question_${this.currentQuestion.id}`;
    this.myForm = this.fb.group({
      [this.currentControlName]: ['', Validators.required],
    });
  }

  goToNextQuestion(): void {
    const currentIndex = this.questions.findIndex(q => q.id === this.currentQuestion.id);
    const nextIndex = currentIndex + 1;
    if (nextIndex < this.questions.length) {
      this.currentQuestion = this.questions[nextIndex];
      this.currentControlName = `question_${this.currentQuestion.id}`;
      this.myForm = this.fb.group({
        [this.currentControlName]: ['', Validators.required],
      });
    }
  }
}

minimal.component.html

<form [formGroup]="myForm">
    <label>{{ currentQuestion.label }}</label>
    <input type="text" [formControlName]="currentControlName">
    <button type="button" (click)="goToNextQuestion()">Next Question</button>
</form>
html angular dom angular-reactive-forms
1个回答
0
投票

需要一个与 HTML 上的表单控件关联的输入,我们不能用不同的表单控件名称交换输入并期望它能够工作!这是另一种方法,您可以在开始时设置输入,然后使用 HTML 属性

hidden
我们隐藏/显示当前值,该值是使用
currentQuestionIndex
中的索引进行跟踪的,这似乎效果很好!

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

interface Question {
  id: string;
  label: string;
}

@Component({
  selector: 'app-minimal-form',
  template: `
    <form [formGroup]="myForm">
      <ng-container *ngFor="let question of questions; trackBy: track; let i = index">
        <span [hidden]="i !== currentQuestionIndex">
          <label>{{ questions[i].label }}</label>
          <input type="text" [formControlName]="'question_' + question.id">
        </span>
      </ng-container>
      <button type="button" (click)="goToNextQuestion()">Next Question</button>
    </form>

    {{myForm.value | json}}
  `,
})
export class AppComponent {
  myForm: FormGroup;
  currentQuestion: Question;
  questions: Question[] = [
    { id: 'A', label: 'Question A' },
    { id: 'B', label: 'Question B' },
  ];
  currentQuestionIndex: number = 0;

  constructor(private fb: FormBuilder) {}

  track(index: number, item: Question) {
    return item.id;
  }

  ngOnInit(): void {
    this.currentQuestion = this.questions[0];
    this.myForm = this.fb.group({});
    this.currentQuestionIndex = 0;
    this.questions.forEach((question: Question) => {
      this.myForm.addControl(
        `question_${question.id}`,
        this.fb.control('', Validators.required)
      );
    });
  }

  goToNextQuestion(): void {
    this.currentQuestionIndex++;
  }
}

Stackblitz Demo

© www.soinside.com 2019 - 2024. All rights reserved.