如何使用设置控件方法填充FormArray的值?

时间:2019-07-28 15:34:10

标签: angular angular-reactive-forms angular8

我对动态输入字段有反应形式。我使用FormArray生成了这些字段。现在,我正在尝试使用编辑屏幕上的数据预填充表单,但无法执行。我尝试使用setControl方法填充此错误Cannot find control with path: 'books -> 0 -> name'

这些是我参考的来源

  1. https://alligator.io/angular/reactive-forms-formarray-dynamic-fields/
  2. https://stackoverflow.com/a/44988197/9715025
  3. https://stackoverflow.com/a/42599327/9715025

组件

import { Component } from '@angular/core';
import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface ServerResponse {
  books: any;
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  formGroup: FormGroup;
  books: FormArray;

  constructor(
    private http: HttpClient,
    private formBuilder: FormBuilder,
  ) {

  }

  createForm() {
    this.formGroup = this.formBuilder.group({
      books: this.formBuilder.array([this.createBookForm()]),
    });
  }

  createBookForm() {
    return this.formBuilder.group({
      name: [],
      author: [],
    });
  }

  addBook() {
    this.books = this.formGroup.get('books') as FormArray;
    this.books.push(this.createBookForm());
  }

  getData(): Observable<ServerResponse> {
    return this.http.get<ServerResponse>('https://demo0331989.mockable.io/library/data/book');
  }

  populateData() {
    this.getData().subscribe(data => {
      this.formGroup.setControl('books', this.formBuilder.array(data.books || []));
    });
  }

  ngOnInit() {
    this.createForm();
    this.populateData();
  }
}

HTML

<form [formGroup]="formGroup">
  <div formArrayName="books" *ngFor="let book of formGroup.get('books')['controls']; let i = index;">
    <div class="row" [formGroupName]="i">
      <input type="text" autocomplete="off" placeholder="*Name"
      formControlName="name">
      <input type="text" autocomplete="off" placeholder="*Author"
      formControlName="author">
      <button type="button" class="btn btn-success" (click)="addBook();">Add</button>
    </div>
  </div>
</form>

我也正在共享Stackblitz中的代码。样本/模拟data要预先填充。我不确定我在这里缺少什么!

3 个答案:

答案 0 :(得分:0)

I did a fork from your stackblitz example,请看一看。当您要预先填充表单时,需要创建BookForm并将其传递给setControl,而不仅仅是数组。

答案 1 :(得分:0)

填充表单数组时,您需要使用填充的表单组填充它,因此它看起来像这样:

populateData() {
  this.getData().subscribe(data => {
    const books = this.formGroup.get('books') as FormArray; // get the array
    books.clear(); // clear the array 
    data.books.forEach(b => { // iterate data
      let fg = this.createBookForm(); // create the group
      fg.reset(b); // fill the data
      books.push(fg); // add to array
    });
    this.addBook(); // add blank form to end if desired
  });
}

可能不需要也可能不需要清除表单部分/在末尾添加空白。

这是固定的闪电战:https://stackblitz.com/edit/angular-9ts4yv?file=src/app/app.component.ts

答案 2 :(得分:0)

免责声明,此答案与@ bryan60答案

是互补的

我喜欢我的函数createBookForm具有参数“ data”,所以

createBookForm(data:any) {
    data=data||{name:null,author:null}
    return this.formBuilder.group({
      name: data.name,
      author: data.author,
    });
  }

这允许我们写

createBookForm(null) //create a FormGroup with name and author and values null
//or 
createBookForm({name:"Linus Administration",author:"Roger"}) //the formgroup has values

我们的函数populateData变得更加简单

  populateData() {
    this.getData().subscribe(data => {
      const books = this.formGroup.get('books') as FormArray;
      books.clear();
      data.books.forEach(b => {
        books.push(this.createBookForm(b))
      });
    });
  }

注意:我看不到声明具有唯一属性FormForm的formGroup的必要性,请参见stackoverflow question

中的其他回答