更新FormGroup中的FormArray时更改检测不起作用

Jus*_*ead 5 angular angular-reactive-forms

使用反应形式并在推送时进行更改检测。

我一直在SO中搜寻如何做这个例子,我觉得这很普遍,但是,我似乎找不到如何正确地做一个好例子。

尝试更新包含在ngOnInit内的订阅中的FormGroup列表的FormArray时,将更新FormArray对象,但除非在组件上强制进行更改检测,否则视图将不会更新FormArray组。以这种方式更新的所有其他控件都在工作。因此,感觉就像我尝试更新FormArray是错误的,并且我不应该并且不想强制更改检测。

import { Component, OnInit, ChangeDetectionStrategy } from "@angular/core";
import { JournalTransactionService } from "app/accounting/shared-services/journal-transaction.service";
import { JournalEntry } from "accountingModels";
import { FormBuilder, FormGroup, FormArray } from "@angular/forms";
import { EntryLine } from "app/accounting/models/journal";

@Component({
  selector: "general-journal",
  templateUrl: "./general-journal.component.html",
  styleUrls: ["./general-journal.component.scss"],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class GeneralJournalComponent implements OnInit {
  journalEntry: JournalEntry;
  journalEntryForm: FormGroup;

  constructor(private _journalTransactionService: JournalTransactionService, private _formBuilder: FormBuilder) { }

  get entryLines(): FormArray {
    return <FormArray>this.journalEntryForm.get("entryLines");
  };

  ngOnInit() {
    this.journalEntryForm = this._formBuilder.group(
      {
        transactionId: "",
        transactionDate: "",
        autoReversalDate: "",
        journalEntryType: "",
        entryLines: this._formBuilder.array([])
      }
    );
    this._journalTransactionService.getTransaction("", 80).subscribe(journalEntry => {
      journalEntry.entryLines.forEach(entryLine => {
        this.entryLines.push(this.entryLineMapper(entryLine));
      });

      this.journalEntryForm.patchValue(
        {
          transactionId: journalEntry.transactionId,
          transactionDate: journalEntry.transactionDate,
          autoReversalDate: journalEntry.autoReversalDate,
          journalEntryType: journalEntry.journalEntryType
        }
      );
    });
  }


  private entryLineMapper = (entryLine: EntryLine): FormGroup => {
    return this._formBuilder.group({
      accountId: entryLine.accountId,
      controlId: entryLine.controlId,
      debit: entryLine.debit,
      credit: entryLine.credit,
      description: entryLine.description,
    })
  }
}
Run Code Online (Sandbox Code Playgroud)

html的相关部分。如果您键入绑定的任何其他字段(例如事务ID),那么将运行更改检测并填写表格。如果在订阅块中的补丁值之后手动触发更改检测,则会填写该表。

  <tbody formArrayName="entryLines">
      <tr *ngFor="let entryLine of entryLines.controls; index as i" [formGroupName]="i">
        <td>
          <input type="text" class="form-control" formControlName="accountId">
        </td>
        <td>
          <input type="text" class="form-control" formControlName="controlId">
        </td>
        <td>
          <input type="text" class="form-control" formControlName="debit">
        </td>
        <td>
          <input type="text" class="form-control" formControlName="credit">
        </td>
        <td>
          <input type="text" class="form-control" formControlName="description">
        </td>
      </tr>
    </tbody>
Run Code Online (Sandbox Code Playgroud)

更新资料

为了解决这个问题,我现在要创建两个组件,一个是功能的基本组件,另一个是包装表单的组件。这使我可以将用于构建表单的数据作为输入传递给表单组件,从而使OnPush检测有效。我对此还可以,但仍然感觉像FormArray应该能够通过订阅添加FormGroups或控件,并在UI中更新新值。我认为,如果FormArray控件是AbstracControl的可观察对象,那么它将起作用。如果有人有更好的解决方案,请告诉我们。

Joe*_*ene 0

不要使用map而只是使用push.

private entryLineBuilder = (entryLines: EntryLine[]): FormArray => {
    return this._formBuilder.array(entryLines.push(this.entryLineMapper));
  }
Run Code Online (Sandbox Code Playgroud)

因为您通过推动来更改阵列,所以这应该会触发角度变化检测。