Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use mat-autocomplete (Angular Material Autocomplete) inside FormArray (Reactive Forms)

let's say I have the following form structure:

  this.myForm = this.formBuilder.group({
          date: ['', [Validators.required]],
          notes: [''],
          items: this.initItems()

        });
  initItems() {
    var formArray = this.formBuilder.array([]);
    for (let i = 0; i < 2; i++) {
      formArray.push(this.formBuilder.group({
        name: ['', [Validators.required]],
        age: ['', [Validators.required]],
      }));
    }

    return formArray;
  }

and the name control supposed to be an autocomplete, how can I relate the all the name controls to an autocomplete list?

like image 416
Furqan S. Mahmoud Avatar asked Jul 27 '18 17:07

Furqan S. Mahmoud


People also ask

How do I use angular material autocomplete?

Start by creating the autocomplete panel and the options displayed inside it. Each option should be defined by a mat-option tag. Set each option's value property to whatever you'd like the value of the text input to be when that option is selected.

How is FormArray used in reactive form?

Binding FormArray to Template We use the formArrayName directive to bind the skills form array to the div element. Now the div and anything inside the div element is bound to the skills form array. Inside the div use ngFor to loop through each element of skills FormArray.

Can I use FormArray without FormGroup?

You just need to name the formControls inside your formArray .


1 Answers

I solved this by relating each name control inside the FormArray to a filteredOption array:

  ManageNameControl(index: number) {
    var arrayControl = this.myForm.get('items') as FormArray;
    this.filteredOptions[index] = arrayControl.at(index).get('name').valueChanges
      .pipe(
      startWith<string | User>(''),
      map(value => typeof value === 'string' ? value : value.name),
      map(name => name ? this._filter(name) : this.options.slice())
      );

  }

Then After each time I build a formgroup inside the form Array (create new item), I need to call the above function at the new index like this:

  addNewItem() {
    const controls = <FormArray>this.myForm.controls['items'];
    let formGroup = this.formBuilder.group({
      name: ['', [Validators.required]],
      age: ['', [Validators.required]],
    });
    controls.push(formGroup);
    // Build the account Auto Complete values
    this.ManageNameControl(controls.length - 1);

  }

In the .html file, we need to refer to the desired filteredOption array, we can do this by using the i index:

  <mat-option *ngFor="let option of filteredOptions[i] | async " [value]="option">
  {{ option.name }}
  </mat-option>

please see the detailed answer here https://stackblitz.com/edit/angular-szxkme?file=app%2Fautocomplete-display-example.ts

Update: to populate the array with a default value for a specific object, you can do it using the receive forms like this:

 let formGroup = this.fb.group({
      name: [{value: { name: 'Mary' } , disabled: false}, [Validators.required]],
      age: ['', [Validators.required]],
    });

stackblitz

like image 71
Furqan S. Mahmoud Avatar answered Oct 07 '22 16:10

Furqan S. Mahmoud