6

I have a FormGroup that has an element like this.

books: this.fb.array([this.buildBookFormGroup()])

fb is the FormBuilder. The buildBookFormGroup() function returns a FromGroup so that I can add/remove multiple books from the same form.

buildBookFormGroup(): FormGroup {
    return this.fb.group({
      author: new FormControl(''),
      price: new FormControl(0),
    });
  }

I have functions for getting the form controls, for adding and for removing formgroups from the 'books' control.

Now, I have added multiple books using this form and persisted them. I want to make an edit page where I want to fetch the existing data and populate the form. For that, I am using 'patchValue'. However, patchValue is not working for FormArray. Looked into multiple questions and answers, and I'm further confused. Here is how I was patching.

if (this.bookshop.books.length > 0) {
      let booksFormGroupArray: FormGroup[] = [];
      this.bookshop.books.forEach((book, index) => {
        booksFormGroupArray.push(this.buildBookFormGroup());
        Object.keys(booksFormGroupArray[index].controls).forEach(key => {
          booksFormGroupArray[index].patchValue({
            [key]: book[key]
          })
        })
      });
      this.bookForm.patchValue({
        books: this.fb.array(booksFormGroupArray)
      });
    }

Only the first book object is getting inserted into the 'books' of the form. Is there any workaround?

1

1 Answer 1

7

When you use patchValue you have to provide value not an array of FormGroups.

So, you patch value directly to dynamically created FormGroups and push the group into the controls of your array, it will work.

So, new patching method will be:

if (this.bookshop.books.length > 0) {
      const bookArray = this.bookForm.get("books") as FormArray;
      bookArray.clear();

      this.bookshop.books.forEach(book => {
        const group = this.buildBookbookFormGroup();
        Object.keys(group.controls).forEach(key => {
          group.patchValue({
            [key]: book[key]
          });
        });
        bookArray.controls.push(group);
      });
    }

And if you want to iterate over FormArray values, then:

get books() {
    return (this.bookForm.get("books") as FormArray).controls.map(m => m.value);
}

HTML:

<div *ngFor="let book of books">
    <p>Author: {{book.author}}, &emsp; Price: {{book.price}}</p>
</div>

Working demo at StackBlitz.

Result:

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

I'm not sure you need the Object.keys... statement. FormBuilder.group() should do that for you.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.