web-dev-qa-db-ja.com

Angular 2/4 Edit Form Populate FormArray Controls

ネストされた属性(FormArray)を持つモデルの編集フォームを実装しようとしています。構文に問題があり、正しい軌道に乗っているかどうかはわかりません。メインフォームの属性は機能しますが、それは私が問題を抱えているネストされたフォームです。ここに私がこれまで持っているものがあります。

ここでフォームグループを開始します。

private initForm() {
  this.subscription = this.expenseService.getExpense(this.id)
    .subscribe(
      expense => {
        this.expense = expense;
        this.patchForm();
      }
    );
  this.expenseEditForm = this.fb.group({
    date: '',
    amount: '',
    check_number: '',
    debit: '',
    payee_id: '',
    notes: '',
    expense_expense_categories_attributes:[]
  });
}

ここで、フォームにパッチを適用して、バックエンドAPIから取得したオブジェクトの値を設定します。

private patchForm() {
  this.expenseEditForm.setValue({
    date: '',
    amount: this.expense.amount_cents,
    check_number: this.expense.check_number,
    debit: this.expense.debit,
    payee_id: '',
    notes: this.expense.notes,
    expense_expense_categories_attributes:  this.fb.array([
      this.setExpenseCategories(),
    ])
  });
}

これは私が立ち往生しているところです。 FormArrayにプッシュするにはどうすればよいですか。プッシュしようとすると、プッシュがFormArrayに存在しないというエラーが表示されます。

private setExpenseCategories() {
  for ( let expenseCategories of this.expense.expense_expense_categories){
    this.fb.array.Push([
       this.fb.group({
        expense_category_id: [expenseCategories.expense_category_id, Validators.required],
        amount: [expenseCategories.amount_cents]
      ])
    });
  }
}

必要な場合に備えて。これが私のhtmlです。

<div
  *ngFor="let expensecategoriesCtl of expenseEditForm.controls.expense_expense_categories_attributes.controls let i = index"
  [formGroupName]="i"
  style="margin-top: 10px;">

  <md-card>
    <md-select class="full-width-input"
               placeholder="Expense Category"
               id="expense_category_id"
               formControlName="expense_category_id"
    >

      <md-option *ngFor="let expenseCategory of expenseCategories" value="{{expenseCategory.id}}">
        {{expenseCategory.category}}
      </md-option>
    </md-select>

    <md-input-container class="full-width-input">
      <input
        mdInput placeholder="Amount"
        type="number"
        formControlName="amount">
    </md-input-container>
  </md-card>
</div>
11
ctilley79

expense.expense_expense_categoriesはプリミティブ型ではなくオブジェクトを含むため、DeborahKの答えにいくつかの変更が加えられました。したがって、値をそのまま割り当てることはできませんが、各オブジェクトは、試みたようにFormGroupでラップする必要があります。

ここにコードの短縮版があります:

フォームを作成します。

ngOnInit() {
  this.expenseEditForm = this.fb.group({
    notes: [''],
    // notice below change, we need to mark it as an formArray
    expense_expense_categories_attributes: this.fb.array([])
})

次に、コールバックでpatchFormを呼び出します。その関数は次のようになります。注意してください、外部でthis.setExpenseCategoriesを呼び出します:

patchForm() {
  this.expenseEditForm.patchValue({
    notes: this.expense.notes,
  })
  this.setExpenseCategories()
}

次に、既存のコードから最大の変更があります。最初にFormArrayを変数controlに割り当ててから、バックエンドから受け取った配列を反復処理し、それぞれに対してFormGroupを作成しますオブジェクトと各FormGroupにオブジェクトをプッシュします。

setExpenseCategories(){
  let control = <FormArray>this.expenseEditForm.controls.expense_expense_categories_attributes;
  this.expense.expense_expense_categories.forEach(x => {
    control.Push(this.fb.group(x));
  })
}

次に、テンプレートに対して、この例ではAngular Material:

<form [formGroup]="expenseEditForm">
  <label>Notes: </label>
  <input formControlName="notes" /><br>
  <!-- Declare formArrayName -->
  <div formArrayName="expense_expense_categories_attributes">
    <!-- iterate formArray -->
    <div *ngFor="let d of expenseEditForm.get('expense_expense_categories_attributes').controls; let i=index"> 
      <!-- Use the index for each formGroup inside the formArray -->
      <div [formGroupName]="i">
      <label>Amount: </label>
        <input formControlName="amount" />
      </div>
    </div>
  </div>
</form>

最後に

デモ

14
AJT82

私があなたの質問を正しく理解しているなら、あなたはこのような何かを必要とするかもしれません:

    // Update the data on the form
    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 || []));

完全な例をここで見ることができます: https://github.com/DeborahK/Angular2-ReactiveForms APM-Updatedフォルダー。

2
DeborahK