web-dev-qa-db-fra.com

Angular 2/4 Edit Form Populate FormArray Controls

J'essaie d'implémenter un formulaire d'édition pour un modèle avec des attributs imbriqués (FormArray). J'ai des problèmes avec la syntaxe et je ne sais pas si je suis sur la bonne voie. Les attributs du formulaire principal fonctionnent, c'est le formulaire imbriqué avec lequel j'ai des problèmes. Voici ce que j'ai jusqu'à présent.

Ici, j'initie le groupe de formulaires:

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:[]
  });
}

Ici, je corrige le formulaire pour définir les valeurs d'un objet récupéré de mon API backend.

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(),
    ])
  });
}

C'est là que je suis coincé. Comment puis-je pousser sur un FormArray. Si j'essaie de pousser, j'obtiens une erreur indiquant que Push n'existe pas sur 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]
      ])
    });
  }
}

Juste au cas où cela serait nécessaire. Voici mon 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

Quelques changements dans la réponse de DeborahK, puisque expense.expense_expense_categories ne contient pas de types primitifs, mais des objets. Par conséquent, nous ne pouvons pas affecter les valeurs telles quelles, mais chaque objet doit être enveloppé dans un FormGroup, comme vous l'avez tenté.

Ici, j'ai une version abrégée de votre code:

Créez le formulaire:

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([])
})

Ensuite, nous appelons patchForm dans le rappel, tout comme vous l'avez fait. Cette fonction ressemblerait à ceci, remarquez, nous appelons this.setExpenseCategories à l'extérieur:

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

Vient ensuite le plus grand changement par rapport à votre code existant, où nous attribuons d'abord le FormArray à la variable control puis nous itérons votre tableau reçu du backend, créons un FormGroup pour chaque objet et pousser l'objet à chaque 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));
  })
}

Ensuite, pour le modèle, cet exemple est sans 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>

Enfin un

Démo

14
AJT82

Si je comprends bien votre question, vous aurez peut-être besoin de quelque chose comme ceci:

    // 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 || []));

Vous pouvez voir l'exemple complet ici: https://github.com/DeborahK/Angular2-ReactiveForms dans le dossier APM - Updated.

2
DeborahK