【问题标题】:Angular FormArray patchValue error: TypeError: value.forEach is not a function - how to resolve?Angular FormArray patchValue 错误:TypeError: value.forEach 不是函数 - 如何解决?
【发布时间】:2018-03-11 17:39:08
【问题描述】:

页面最初是作为模板驱动的表单编写的,但正在被转换为响应式以添加自动保存功能。

在页面组件的构造函数中,我定义了响应式表单变量:

 this.form = fb.group({
    reviewer: '',
    position: '',
    officeName: '',
    rows: fb.array([]),
    comments1: '',
    comments2: '',
    comments3: ''
});

'rows' 是与此问题相关的字段。

在 ngInit 中,通过 Web api 发出请求以检索持久的表单数据。数据以行数组的形式检索,每行包含 6 个单元格的数组。第三个单元格将绑定到 FormControl,其他单元格将呈现为静态文本。

this.rows = summaryReportQuestion.map(summaryReportQuestionObj => {
    return {
        cells: [
            summaryReportQuestionObj.questionID,
            summaryReportQuestionObj.question,
            (summaryReportQuestionObj.columnSign == '$' ? (summaryReportQuestionObj.columnSign + ' ' + summaryReportQuestionObj.target) : summaryReportQuestionObj.target + ' ' + summaryReportQuestionObj.columnSign),
            (summaryReportQuestionObj.budget == null ? summaryReportQuestionObj.budget : (summaryReportQuestionObj.columnSign == '$' ? summaryReportQuestionObj.columnSign + ' ' + this.utilityService.formatNumberWithCommas(Math.floor(summaryReportQuestionObj.budget), false) : summaryReportQuestionObj.budget + ' ' + summaryReportQuestionObj.columnSign)),
            (summaryReportQuestionObj.average == null ? summaryReportQuestionObj.average : (summaryReportQuestionObj.columnSign == '$' ? summaryReportQuestionObj.columnSign + ' ' + this.utilityService.formatNumberWithCommas(Math.floor(summaryReportQuestionObj.average), false) : summaryReportQuestionObj.average + ' ' + summaryReportQuestionObj.columnSign)),
            (summaryReportQuestionObj.top20Percent == null ? summaryReportQuestionObj.top20Percent : (summaryReportQuestionObj.columnSign == '$' ? summaryReportQuestionObj.columnSign + ' ' + this.utilityService.formatNumberWithCommas(Math.floor(summaryReportQuestionObj.top20Percent), false) : summaryReportQuestionObj.top20Percent + ' ' + summaryReportQuestionObj.columnSign))
        ]
    };
});

let faRows = new FormArray([]);
for (var i = 0, len = this.rows.length; i < len; i++) {
    let row = this.rows[i].cells;
    for (var j = 0, length = this.rows[i].cells.length; j < length; j++) {
        let fc = new FormControl(this.rows[i].cells[j]);
        faRows.push(fc);
    }
}

// this.form.setValue({rows: faRows});
// this.form.setControl('rows', faRows);

在html中:

<tbody>
    <tr *ngFor="let row of rows;let r = index" [attr.data-index]="r">
        <ng-container>
            <td *ngFor="let cell of row.cells;let i = index" [attr.data-index]="i">
                <span *ngIf="i != 2">{{cell}}</span>
                <!-- <input type="text" formControlName="form.rows[r]" *ngIf="i == 2"> -->
            </td>
        </ng-container>
    </tr>
</tbody>

根据评论和答案,我已经阐明了我的意图和代码。 [谢谢@amal 和@DeborahK] 我现在只将每行中的一个数据单元格绑定到 FormControl,每行中的其他单元格显示为: {{细胞}}

因此我需要渲染this.rows(如html所示)和this.form.rows的内容。

我目前在理解如何完成此操作时遇到两个问题。在打字稿中,留下循环的最后块迭代创建行的 FormControls 的数据行,数组 faRows 恰好包含我所期望的,一个 FormArray 的 FormControls,并且每个都检索到它的正确关联保存值。但是,当尝试从 this.rows 复制数据以创建 form.rows 的 FormControls 时,我无法让 setValue 或 setControl 正常工作。这可能与html页面上FormControl的命名有关,这是我的第二个问题。

我不清楚如何引用表单变量以在html中动态创建formControlName。这是我想象的,但它不起作用。

 <input type="text" formControlName="form.rows[r]" *ngIf="i == 2">

【问题讨论】:

  • 只看代码,我感觉你对初始化formArray的赋值不对。您是否期望 1 个单元格中的每个元素都有一个 formArray 控件?比如 questionId、question、columnSign、budget 等?
  • @amal:我已经修改了原始代码,因为我不打算为 1 行中的每个元素设置一个 formArray 控件。相反,只有 1 个元素(第三个,实际的)将具有关联的 FormControl。你能解释一下我是如何混合这两个数组的,一个不是反应式的吗?
  • 还不清楚你想做什么以及你做错了什么。如果您想将反应式 formArray 控件引用到模板,您还需要引用并使用 formArrayName。您能否创建一个复制品或展示您希望此页面最终的外观(您的目标是什么)?

标签: angular reactive-forms formarray


【解决方案1】:

据我所知,无法使用 FormArray 调用 .patchValue。

我的表单设置类似,其中 tags 是我的 FormArray。

    this.productForm = this.fb.group({
        productName: ['', [Validators.required,
                           Validators.minLength(3),
                           Validators.maxLength(50)]],
        productCode: ['', Validators.required],
        starRating: ['', NumberValidators.range(1, 5)],
        tags: this.fb.array([]),
        description: ''
    });

在为编辑设置数据时,我必须这样做:

    this.productForm.patchValue({
        productName: this.product.productName,
        productCode: this.product.productCode,
        starRating: this.product.starRating,
        description: this.product.description
    });
    this.productForm.setControl('tags', this.fb.array(this.product.tags || []));

我对每个简单的 FormControls 使用 patchValue,对 FormArray 使用 setControl

您可以尝试一下,看看是否能解决您的问题。

【讨论】:

  • 仅供参考 - patchValue 确实适用于 FormArray,但它不会调整数组的大小,因此它仅在您设置的数据与 FormArray 的长度相同时才有效。 (对这个问题没有帮助,但需要注意)
  • 这真的很有帮助。我有嵌套的表单组,其中包括表单数组等,实际上是一个相当复杂的表单。我遇到了各种错误和奇怪的行为,其中包括表单数组未更新和控件变得无效或按要求标记,即使它们不是。这个答案帮助我解决了它。最后我使用了patchValue,但随后不得不循环遍历所有控件并为每个嵌套控件使用SetControl。
猜你喜欢
  • 1970-01-01
  • 2019-12-19
  • 2019-11-02
  • 2021-06-21
  • 1970-01-01
  • 2022-10-15
  • 2018-12-20
  • 2021-07-04
  • 2015-06-26
相关资源
最近更新 更多