1

I'm working on an Angular project where I need to implement a form that includes a FormArray with multiple FormControl instances, each using PrimeNG's Autocomplete component with multiple selection enabled. I'm having trouble figuring out how to bind the selected values from the Autocomplete component to the FormArray.

Here's a simplified version of what I'm trying to achieve:

I have a FormArray that dynamically generates a list of FormControl instances.

Each FormControl should be associated with a PrimeNG Autocomplete component that allows multiple selections.

When the user selects multiple items from the Autocomplete, those selected items should be stored in the corresponding FormControl.

Here's a snippet of my current setup:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, FormControl } from '@angular/forms';

@Component({
  selector: 'app-my-form',
  templateUrl: './my-form.component.html',
  styleUrls: ['./my-form.component.css']
})
export class MyFormComponent implements OnInit {
  myForm: FormGroup;
  suggestions: any[] = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.myForm = this.fb.group({
      items: this.fb.array([this.createItem()])
    });
  }

  createItem(): FormGroup {
    return this.fb.group({
      selectedItems: new FormControl([])
    });
  }

  get items(): FormArray {
    return this.myForm.get('items') as FormArray;
  }

  addItem() {
    this.items.push(this.createItem());
  }

  removeItem(index: number) {
    this.items.removeAt(index);
  }
}

And the corresponding HTML:

<form [formGroup]="myForm">
  <div formArrayName="items">
    <div *ngFor="let item of items.controls; let i = index" [formGroupName]="i">
      <p-autoComplete 
        formControlName="selectedItems"
        [suggestions]="suggestions"
        [multiple]="true"
        (completeMethod)="filterSuggestions($event)"
        field="name">
      </p-autoComplete>
    </div>
  </div>
  <button type="button" (click)="addItem()">Add Item</button>
</form>
  1. How do I properly bind the selected values from the PrimeNG Autocomplete component to the FormControl within the FormArray?

  2. Is there a specific way to handle the completeMethod to filter suggestions dynamically for each FormControl in the FormArray?

  3. Are there any common pitfalls or best practices when using PrimeNG Autocomplete with Angular's reactive forms, especially with FormArray?

Any help or guidance would be greatly appreciated! Thanks in advance.

1 Answer 1

0
  1. You can remove field property this is meant to be used only when you are using an array of objects for the dropdown [{id: 1, name: 'apple'}].

     <p-autoComplete
       formControlName="selectedItems"
       [suggestions]="suggestions"
       [multiple]="true"
       (completeMethod)="search($event)"
     >
     </p-autoComplete>
    
  2. You should maintain two copies of the dropdown object, one for storing the original values and another you use to show the filtered values from the input typed by the user.

     suggestions: any[] = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];
     suggestionsBackup: any[] = [
         'Apple',
         'Banana',
         'Cherry',
         'Date',
         'Elderberry',
     ];
     ...
    
     ...
     search(event: AutoCompleteCompleteEvent) {
         this.suggestions = this.suggestionsBackup.filter((item: string) =>
         item.toLowerCase().includes(event.query.toLowerCase())
         );
     }
    

Apart from this all seems good, you might want to use the new angular control flow which needs zero imports.

Full Code:

HTML:

    <form [formGroup]="myForm">
    <div formArrayName="items">
        @for(item of items.controls; let i = $index;track i) {
            <div [formGroupName]="i">
            <p-autoComplete
                formControlName="selectedItems"
                [suggestions]="suggestions"
                [multiple]="true"
                (completeMethod)="search($event)"
            >
            </p-autoComplete>
            </div>
        }
    </div>
    <button type="button" (click)="addItem()">Add Item</button>
    </form>

    <div>{{myForm.value | json}}</div>

TS:

import { Component } from '@angular/core';
import { ImportsModule } from './imports';
import { AutoComplete } from 'primeng/autocomplete';
import { FormGroup, FormBuilder, FormControl, FormArray } from '@angular/forms';

interface AutoCompleteCompleteEvent {
  originalEvent: Event;
  query: string;
}

@Component({
  selector: 'autocomplete-basic-demo',
  templateUrl: './autocomplete-basic-demo.html',
  imports: [ImportsModule],
  standalone: true,
})
export class AutocompleteBasicDemo {
  myForm: FormGroup;
  suggestions: any[] = ['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'];
  suggestionsBackup: any[] = [
    'Apple',
    'Banana',
    'Cherry',
    'Date',
    'Elderberry',
  ];

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    this.myForm = this.fb.group({
      items: this.fb.array([this.createItem()]),
    });
  }

  createItem(): FormGroup {
    return this.fb.group({
      selectedItems: new FormControl([]),
    });
  }

  get items(): FormArray {
    return this.myForm.get('items') as FormArray;
  }

  addItem() {
    this.items.push(this.createItem());
  }

  removeItem(index: number) {
    this.items.removeAt(index);
  }

  search(event: AutoCompleteCompleteEvent) {
    this.suggestions = this.suggestionsBackup.filter((item: string) =>
      item.toLowerCase().includes(event.query.toLowerCase())
    );
  }
}

Stackblitz Demo

3
  • Thank you for your response. However, what this does is create another autocomplete input. What I'm trying to achieve is to add to the multiple (Chips). Commented Feb 8 at 11:49
  • I was able to make it work to some extent, I just need to add the <formArrayName="items">. Commented Feb 8 at 11:59
  • @syahiruddin please share the output your are expected (form value structure and what is wrong in the stackblitz Commented Feb 8 at 12:05

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.