Estoy tratando de implementar un formulario de edición para un modelo con atributos anidados (FormArray). Tengo problemas con la sintaxis y no estoy seguro de si estoy en el camino correcto. Los atributos para el formulario principal funcionan, es el formulario anidado con el que tengo problemas. Esto es lo que tengo hasta ahora.
Aquí inicio el formulario de grupo:
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:[] }); }Aquí parcheo el formulario para establecer valores de un objeto recuperado de mi API de back-end.
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(), ]) }); }Aquí es donde estoy atascado. ¿Cómo presiono en un FormArray. Si trato de empujar, aparece un error que indica que empujar no existe en 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] ]) }); } }Por si acaso es necesario. Aquí está mi 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>Algunos cambios en la respuesta de DeborahK, ya que expense.expense_expense_categories no contiene tipos primitivos, sino objetos. Por lo tanto, no podemos asignar los valores tal como están, pero cada objeto debe estar envuelto en un FormGroup , tal como lo ha intentado.
Aquí tengo una versión abreviada de su código:
Construye el formulario:
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([]) }) Luego llamamos patchForm en la devolución de llamada, tal como lo ha hecho. Esa función se vería así, observe, llamamos a this.setExpenseCategories afuera:
patchForm() { this.expenseEditForm.patchValue({ notes: this.expense.notes, }) this.setExpenseCategories() } Luego viene el cambio más grande de su código existente, donde primero asignamos FormArray al control de variable y luego iteramos su matriz recibida del backend, creamos un FormGroup para cada objeto y empujamos el objeto a cada 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)); }) }Luego a la plantilla, este ejemplo es sin material angular:
<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>Finalmente un
Si entiendo tu pregunta correctamente, es posible que necesites algo como esto:
// 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 || []));Puede ver el ejemplo completo aquí: https://github.com/DeborahK/Angular2-ReactiveForms en la carpeta APM - Updated.