角-setValue formArrayName

时间:2019-12-24 13:49:10

标签: angular typescript

我有一个包含字符串数组的表单,每次我向列表中添加一个元素时,问题是当我使用setValue设置数组中的值时,它会显示以下错误

<button (click)="addNewCompany()">Add new Company</button><br><br>
<form [formGroup]="myForm">
    <div formArrayName="companies">
        <div *ngFor="let comp of getForm(); let i=index>
            <fieldset>
                <legend>
                    <h3>COMPANY {{i+1}}: </h3>
                </legend>
                <label>Company Name: </label>
                <input [formControlName]="i" /><span><button (click)="deleteCompany(i)">Delete Company</button></span>
            </fieldset>
        </div>
    </div><br>
  </form>


export class AppComponent implements OnInit {

  @Input()
  public product: Product; 

  myForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.myForm = this.fb.group({
      companies: this.fb.array([])
    });
  }

  ngOnInit() {
     this.addNewCompany();
     this.myForm.controls['companies'].setValue(this.product.companies); // error
  }

  getForm(): any {
    return this.myForm.get("companies")["controls"];
  }

  addNewCompany() {
    const control = <FormArray>this.myForm.get("companies");
    control.push(this.fb.control(''));
  }

  deleteCompany(index) {
    let control = <FormArray>this.myForm.controls.companies;
    control.removeAt(index);
  }

}
  

错误错误:没有向该数组注册任何表单控件   然而。如果您使用的是ngModel,则可能要检查下一个勾号(例如   使用setTimeout)。

stackblitz

2 个答案:

答案 0 :(得分:0)

如果您尝试从控件设置companies,则该值必须是一个数组,并确保添加新的表单控件作为数组值的基础

product = {
companies:['company 01' , 'company 02']
} 
ngOnInit() {
  // make sure you have set a default value to product like {companies:[]}
  for (let p of this.product.companies) {
    this.addNewCompany();
  }

  this.myForm.controls['companies'].setValue(this.product.companies);
}
  

如果使用 setValue 方法,则必须提供控件长度的值基,否则,如果数组控件长度小于或等于数组值,则数组长度必须与控件长度相同控制长度。

     

patchValue 没有关于控件长度的约束,但这意味着如果您将公司设置为10,而您只有一个控件,则您只会获得第一家公司,另一个将消失,因此在这种情况下,请确保使用setValue或patchValue,但请确保控件的长度与值

相同

demo ??

答案 1 :(得分:0)

您可以移动在form内创建ngOnInit的逻辑。像这样:

@Input()
public product: Product;

myForm: FormGroup;

constructor(private fb: FormBuilder) {}

ngOnInit() {
  this.myForm = this.fb.group({
    companies: this.fb.array(this.product ? this.product.companies.map(company => new FormControl(company)) : [])
  });
}

addNewCompany() {
  this.companies.push(new FormControl());
}

deleteCompany(i) {
  this.companies.removeAt(i);
}

get companies() {
  return ( < FormArray > this.myForm.get('companies'));
}

但是可能无法保证product @Input属性将在时间之前设置。

因此,为了确保在使用form companies创建FormArray之前已对其进行了设置,您可能需要在其中初始化product属性通过服务代替。

您必须创建一个DataService来为您完成:

import { Injectable } from '@angular/core';
import { Product } from './product.model';

@Injectable()
export class DataService {

  product: Product;

  constructor() { }

  setProduct(product) {
    this.product = product;
  }

}

然后可以将其注入到父组件中以设置product,并注入到子组件中以通过ngOnInit生命周期挂钩方法获得产品。像这样:

myForm: FormGroup;

constructor(
  private fb: FormBuilder,
  private dataService: DataService
) {}

ngOnInit() {
  this.myForm = this.fb.group({
    companies: this.fb.array(this.dataService.product ? this.dataService.product.companies.map(company => new FormControl(company)) : [])
  });
}

addNewCompany() {
  this.companies.push(new FormControl());
}

deleteCompany(i) {
  this.companies.removeAt(i);
}

get companies() {
  return ( < FormArray > this.myForm.get('companies'));
}
  

这是您推荐的Working Sample Demo