Angular 2 Ошибка FormArray

Привет, я пытаюсь отобразить ряд сведений об ингредиентах в моем приложении Angular 2 Recipe. Я использую FormArray, но когда я запускаю свой и использую инструменты разработки браузера для отладки своего кода, я вижу следующую ошибку на вкладке «Консоль». Интересно, может ли кто-нибудь объяснить мне, в чем проблема и что мне нужно сделать, чтобы ее исправить: -

RecipeIngredientsDetailsComponent.html:17 ERROR Error: Cannot find control with path: 's_ingredientDetails -> ingredient_name'
    at _throwError (forms.js:2385)
    at setUpControl (forms.js:2255)
    at FormGroupDirective.addControl (forms.js:6606)
    at FormControlName._setUpControl (forms.js:7256)
    at FormControlName.ngOnChanges (forms.js:7169)
    at checkAndUpdateDirectiveInline (core.js:12092)
    at checkAndUpdateNodeInline (core.js:13598)
    at checkAndUpdateNode (core.js:13541)
    at debugCheckAndUpdateNode (core.js:14413)
    at debugCheckDirectivesFn (core.js:14354)

Ниже приведен код сценария моего типа: -

import { Component, Input, Output, EventEmitter, OnInit, ElementRef } from '@angular/core';
import { FormArray, FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms';
import { Observable } from 'rxjs/Observable';

import { Ingredient } from '../ingredient';
import { IngredientDetailService } from '../ingredient-detail.service';


@Component({
  selector: 'app-recipe-ingredients-details',
  templateUrl: './recipe-ingredients-details.component.html',
  styleUrls: ['./recipe-ingredients-details.component.css'],
  providers: [IngredientDetailService]
})

export class RecipeIngredientsDetailsComponent implements OnInit {

  create_recipe_ingredient_detail_form: FormGroup;
  ingredients_arr: Ingredient[] = [];

  // @Output will tell the parent component (AppComponent) that an event happened in this component
  @Output() show_read_recipes_event = new EventEmitter();

  constructor(
    private formBuilder: FormBuilder,
    private ingredientDetailService: IngredientDetailService

  ) {  }

  @Input()
  r_id: number;

  @Input()
  s_ingredients: Ingredient[];

  ngOnInit() {
    this.create_recipe_ingredient_detail_form = this.formBuilder.group({
      s_ingredientDetails: this.formBuilder.array(
        this.s_ingredients.map(x => this.formBuilder.group({
          ingredient_name: [x.ingredient_name, [Validators.required]],
          ingredient_quantity: ['', [Validators.required]],
          ingredient_comment: ['', [Validators.required]],
        }))
      )
    })
  }

  createRecipeIngredientDetails(): void {
    this.ingredientDetailService.createRecipeIngredientDetails(this.create_recipe_ingredient_detail_form.value)
      .subscribe(
        ingredientDetail => {
          console.log(ingredientDetail);

          this.show_read_recipes_event.emit(
            { title: "Recipe Ingredients details" }
          );
        },
        error => console.log(error)
      );
  }

  dude(){
    console.log(this.s_ingredients);
  }

}

Ниже мой html: -

<div class="row">
    <div class="col-md-12">
      <form [formGroup]="create_recipe_ingredient_detail_form" (ngSubmit)="createRecipeIngredientDetails()">
        <table class="table table-hover table-responsive table-bordered">
          <tr>
            <th>
              Ingredient Name
            </th>
            <th>
              Quantity
            </th>
            <th>
              Comment
            </th>
          </tr>
          <tr formArrayName="s_ingredientDetails" *ngFor="let ingredient of create_recipe_ingredient_detail_form.get('s_ingredientDetails').controls; let i=index">
              <td>
                <div class="form-group">
                  <input name="ingredient_name" formControlName="ingredient_name" class="form-control" id="ingredient.ingredient_id" readonly />           
                </div>
              </td>
              <td>
                <div class="form-group">   
                  <input type="text" name="ingredient_qty" formControlName="ingredient_quantity" class="form-control" id="{{ingredient.ingredient_name}}" />
                </div>
              </td>
              <td>
                <div class="form-group">   
                  <input type="text" name="ingredient_cmt" formControlName="ingredient_comment" class="form-control" id="{{ingredient.ingredient_name}}" />
                </div>
              </td>
          </tr>
          <tr>
            <td>
              <input type="hidden" id="hidden_recipe_id" name="hidden_recipe_id" value="{{r_id}}" />             
            </td>
            <td></td>
            <td>
              <button type="submit" class="btn btn-primary">Create Recipe Ingredient Details</button>
            </td>
          </tr>
        </table>
      </form>
    </div>
  </div>

Ниже приведен снимок экрана, показывающий мою форму во время выполнения: -

введите здесь описание изображения


person ED209    schedule 15.01.2018    source источник


Ответы (2)


Это потому, что ваш массив форм содержит группы форм, и они помечены индексами, вам нужно указать имя группы в шаблоне, чтобы angular мог правильно связать ваши элементы управления с группой, как это

<tr formArrayName="s_ingredientDetails" *ngFor="let ingredient of create_recipe_ingredient_detail_form.get('s_ingredientDetails').controls; let i=index">
    <!--
        Not semantically correct to have a div here, but it will solve the problem.
    -->
  <div [formGroupName]='i'>
    <td>
      <div class="form-group">
        <input name="ingredient_name" formControlName="ingredient_name" class="form-control" id="ingredient.ingredient_id" readonly />           
      </div>
    </td>
    <td>
      <div class="form-group">   
        <input type="text" name="ingredient_qty" formControlName="ingredient_quantity" class="form-control" id="{{ingredient.ingredient_name}}" />
      </div>
    </td>
    <td>
      <div class="form-group">   
        <input type="text" name="ingredient_cmt" formControlName="ingredient_comment" class="form-control" id="{{ingredient.ingredient_name}}" />
      </div>
    </td>
  </div>
</tr>

Кроме того, на дворе 2018 год, перестаньте использовать table для размещения контента.

person Meme Composer    schedule 15.01.2018
comment
Я бы посоветовал вам использовать здесь ng-container вместо div. Тогда все должно быть в порядке семантически) - person yurzui; 15.01.2018
comment
Да, теперь он работает блестяще. Большое спасибо за Вашу помощь. - person ED209; 15.01.2018

Спасибо за помощь Дамми. Вот рабочий html: -

<tr formArrayName="s_ingredientDetails" *ngFor="let ingredient of create_recipe_ingredient_detail_form.get('s_ingredientDetails').controls; let i=index">
            <ng-container [formGroupName]='i'>
                <td>
                  <div class="form-group">
                    <input name="ingredient_name" formControlName="ingredient_name" class="form-control" id="ingredient.ingredient_id" readonly />           
                  </div>
                </td>
                <td>
                  <div class="form-group">   
                    <input type="text" name="ingredient_qty" formControlName="ingredient_quantity" class="form-control" id="{{ingredient.ingredient_name}}" />
                  </div>
                </td>
                <td>
                  <div class="form-group">   
                    <input type="text" name="ingredient_cmt" formControlName="ingredient_comment" class="form-control" id="{{ingredient.ingredient_name}}" />
                  </div>
                </td>
            </ng-container>
          </tr>
person ED209    schedule 15.01.2018