【问题标题】:Reactive FormsModule in Angular2Angular2 中的反应式表单模块
【发布时间】:2019-06-28 10:40:02
【问题描述】:

我在使用 ReactiveFormsModule 时尝试在我的项目中添加 FormsArray,但我收到错误,它显示为:-

找不到具有未指定名称属性的控件。 也不能使用模板驱动的表单来添加 FormsArray 吗?

下面是我的代码。

recipe-edit.component.ts

<div class="row">
<div class="col-xs-12">
<form [formGroup]="recipeform" (ngSubmit)="onsubmit()" #f="ngForm">
  <div class="row">
    <div class="col-xs-12">
      <button
        type="submit"
        class="btn btn-success" 

        >Save</button>
      <button type="button" class="btn btn-danger" >Cancel</button>
    </div>
  </div>
  <div class="row">
    <div class="col-xs-12">
      <div class="form-group">
        <label for="name">Name</label>
        <input
          type="text"
          id="name"
          formControlName="name"
          class="form-control">
      </div>
    </div>
  </div>
  <div class="row">
    <div class="col-xs-12">
      <div class="form-group">
        <label for="imagePath">Image URL</label>
        <input
          type="text"
          id="imagePath"
          formControlName="image"
          class="form-control"
          >
      </div>
    </div>
  </div>
  <div class="row">
    <div class="col-xs-12" >
      <img  class="img-responsive">
    </div>
  </div>
  <div class="row">
    <div class="col-xs-12">
      <div class="form-group">
        <label for="description">Description</label>
        <textarea
          type="text"
          id="description"
          class="form-control"
          formControlName="description"
          rows="6"></textarea>
      </div>
    </div>
  </div>
  <div class="row">
    <div class="col-xs-12" >
      <div
        class="row"
       formArrayName="ingredients"
       *ngFor="let ctrl of recipeform.get('ingredients').controls;let i=index"
        [formGroupName]="i"          
        style="margin-top: 10px;">
        <div class="col-xs-8">
          <input
            type="text"
            formControlName="name"
            class="form-control"
           >
        </div>
        <div class="col-xs-2">
          <input
            type="number"
            class="form-control"
            formControlName="amount"
           >
        </div>
        <div class="col-xs-2">
          <button
            type="button"
            class="btn btn-danger"
           >X</button>
        </div>
      </div>
      <hr>
      <div class="row">
        <div class="col-xs-12">
          <button
            type="button"
            class="btn btn-success"

            >Add Ingredient</button>
        </div>
      </div>
    </div>
  </div>
</form>

recipe-edit.component.ts

import { Component, OnInit, ViewChild } from '@angular/core';
import {NgForm, FormGroup, FormControl, FormArray} from 
'@angular/forms';
import { Recipeservice } from '../recipe.service';
import { ActivatedRoute, Router } from '@angular/router';
@Component({
 selector: 'app-recipe-edit',
templateUrl: './recipe-edit.component.html',
styleUrls: ['./recipe-edit.component.css']
})
export class RecipeEditComponent implements OnInit {
@ViewChild('f') recipeform:FormGroup
id:number
editmode=false
constructor(private reservice:Recipeservice,private 
route:ActivatedRoute,router:Router) { }

ngOnInit() {
this.route.params.subscribe(
  (params)=>{
    this.id=+params['id']
    console.log(this.id)

    this.initform()
  }
)


}
 onsubmit(){
console.log(this.recipeform)
}
private initform(){
let recipename=''
let recipeimage=''
let recipedescription=''
let recipeingredients=new FormArray([])
this.editmode=true
if(this.editmode){
  const recipe=this.reservice.getrecipe(this.id)
  recipename=recipe.name
  recipeimage=recipe.imagepath
  recipedescription=recipe.description
  if(recipe.ingredients!=null){
    for(let ingredient of recipe.ingredients){
      recipeingredients.push(new FormGroup({
        'name':new FormControl(ingredient.name),
        'amount':new FormControl(ingredient.amount)
      }))
    }
  }
}
this.recipeform=new FormGroup({
  'name':new FormControl(recipename),
  'image':new FormControl(recipeimage),
  'description':new FormControl(recipedescription),
  'ingredients':recipeingredients
})
}

 }

【问题讨论】:

    标签: angular


    【解决方案1】:

    我完全同意 @DeborahK 在之前的 answer 中提出的建议,您应该在使用响应式表单时遵循这些建议。

    但是,这些并不是您出错的原因。在您的 HTML 模板中,您的 FormArray 控件的层次结构错误。应该是FormArray --> FormGroup --> FormControl,像这样:

    <div class="row"
            formArrayName="ingredients"
            *ngFor="let ctrl of recipeform.get('ingredients').controls;let i=index"
            style="margin-top: 10px;">
        <div [formGroupName]="i">
            <div class="col-xs-8">
                <input type="text"
                        formControlName="name"
                        class="form-control">
            </div>
            <div class="col-xs-2">
                <input type="number"
                        class="form-control"
                        formControlName="amount">
            </div>
            <div class="col-xs-2">
                <button type="button"
                        class="btn btn-danger">
                    X
                </button>
            </div>
        </div>
    </div>
    

    如您所见,我已将 nameamount 控件包装在 div 中,并将 [formGroupName] 移动到此包装 div。我没有测试代码,但它应该可以解决您的问题。

    【讨论】:

      【解决方案2】:

      编写 Angular 表单的人强烈建议不要混合模板驱动和响应式表单。 FormArray 是响应式表单的一部分。

      您的代码中有一些“模板驱动”表单技术,您应该考虑删除它们,例如:

      @ViewChild('f') recipeform:FormGroup
      

      您正在代码中定义recipeform FormGroup,然后在模板中生成对它的引用,然后将该引用传递回您的代码。 (我很惊讶这不会导致错误。)

      我会推荐:

      1) 从您的模板中删除 #f="ngForm"。这仅适用于模板驱动的表单。

      2) 用 recipeform: FormGroup 的声明替换 @ViewChild('f') recipeform:FormGroup

      3) 使用 FormBuilder 代替 FormGroup 和 FormControl 的实例。

      4)这是异步调用吗:const recipe=this.reservice.getrecipe(this.id),如果是,需要使用subscribe获取数据。

      这是我使用 FormBuilder 和 FormArray 的反应式表单之一的示例:

      export class CustomerComponent implements OnInit {
        customerForm: FormGroup;
      
            ngOnInit() {
              this.customerForm = this.fb.group({
                firstName: ['', [Validators.required, Validators.minLength(3)]],
                lastName: ['', [Validators.required, Validators.maxLength(50)]],
                addresses: this.fb.array([this.buildAddress()])
              });
            }
      
            addAddress(): void {
              this.addresses.push(this.buildAddress());
            }
      
            buildAddress(): FormGroup {
              return this.fb.group({
                addressType: 'home',
                street1: ['', Validators.required],
                street2: '',
                city: '',
                state: '',
                zip: ''
              });
            }
      }
      

      您可以在此处找到完整的工作示例:https://github.com/DeborahK/Angular-ReactiveForms

      我在同一个 repo 中有第二个示例,其中包含与您正在执行的操作类似的参数代码:

        ngOnInit(): void {
          this.productForm = this.fb.group({
            productName: ['', [Validators.required,
                               Validators.minLength(3),
                               Validators.maxLength(50)]],
            tags: this.fb.array([]),
            description: ''
          });
      
          // Read the product Id from the route parameter
          this.sub = this.route.paramMap.subscribe(
            params => {
              const id = +params.get('id');
              this.getProduct(id);
            }
          );
        }
      
        getProduct(id: number): void {
          this.productService.getProduct(id)
            .subscribe(
              (product: Product) => this.displayProduct(product),
              (error: any) => this.errorMessage = <any>error
            );
        }
      
        displayProduct(product: Product): void {
          if (this.productForm) {
            this.productForm.reset();
          }
          this.product = product;
      
          // Update the data on the form
          this.productForm.patchValue({
            productName: this.product.productName,
            description: this.product.description
          });
          this.productForm.setControl('tags', this.fb.array(this.product.tags || []));
        }
      

      如果您对任一示例有任何疑问,请告诉我。

      【讨论】:

        猜你喜欢
        • 2017-12-30
        • 1970-01-01
        • 2017-12-22
        • 2017-05-02
        • 2017-09-13
        • 1970-01-01
        • 1970-01-01
        • 2020-05-05
        • 1970-01-01
        相关资源
        最近更新 更多