Initialize form array without empty input at index 0

user1752532 picture user1752532 · Mar 29, 2017 · Viewed 7.9k times · Source

I am currently constructing an update, add, delete and edit form using angular 2 and reactive forms. I have grouped the controls into a form builder array to dynamically add input controls to the form array. This works fine for an empty form that does not have any items to initialize.

export class ItemsPage{

   collectionForm: FormGroup;
   get items(): FormArray { return <FormArray>this.collectionForm.get('items'); }

   constructor(public formBuilder: FormBuilder){

        this.pageDetails = this.navParams.data;

        this.collectionForm = this.formBuilder.group({
           items: this.formBuilder.array([this.buildItem()])
        });
   }

   buildItem(item?: string): FormGroup {
       return this.formBuilder.group({ item: [item || '', Validators.required] });
   }

   ionViewDidLoad() {
       // Builds a form with pre populated items 
       forEach(this.pageDetails, value => {
           this.items.push(this.buildItem(value));
       })
   }
}

The problem is that the list of controls in the view contain an empty input at index 0 when this.pageDetails has a list of values. This can be removed in the constructor with

this.items.removeAt(0);

However that does not seem right. I thought that maybe I could build the array in its formBuilder.array

let prebuildItems = forEach(this.pageDetails, value => { // lodash forEach
  this.items.push(this.buildItem(value));
});

this.collectionForm = this.formBuilder.group({
  items: this.formBuilder.array([prebuildItems])
});

However when I navigate to the page with that code I get the following error:

Error in ./ItemsPage class ItemsPage - caused by: Cannot read property 'get' of undefined

Answer

Richard Adnams picture Richard Adnams · Mar 29, 2017

I just had a similar issue and I solved it by doing this (I'm adding headers to a FormArray).

addHeader(name = '', value = '') {
    // get headers array control from group
    let headers = <FormArray>this.editForm.controls['options'].controls['headers'];

    // create new header control
    let header = this.fb.group({
        name: [name, Validators.required],
        value: [value]
    });

    // set the value on the control
    // header.setValue({ name, value });

    // add the new control to the array
    headers.push(header);
}

Then when I initially populate the form I just loop over the data and populate the headers.

this.data.headers.forEach(h => {
    this.addHeader(h.name, h.value);
});

I found the information I needed from here Angular Reactive Forms under the section Initialize the "secretLairs" FormArray

I think what I and maybe you are doing is thinking that

this.formBuilder.array([this.buildItem()])

is setting the "schema" for the array, when its actually added a control with value.