Home > Software design >  How do I implement a dropdown which will filter according to input text in the following Angular Mat
How do I implement a dropdown which will filter according to input text in the following Angular Mat

Time:03-24

I would like to implement an auto-complete feature or at least a dropdown with filter option on the following code. ie. when the input field is empty all the options inside array object's name property can be shown, and as and when user types something the dropdown options need to be filtered based on input text. I am completely new to Angular material and came across this code sample on stackblitz .

HTML Code:

    <form  (ngSubmit)="onSubmit()" [formGroup]="registerForm">
    <mat-form-field >
        <mat-chip-list #chipList formArrayName="Tags">
            <mat-chip *ngFor="let tag of tagsArr.controls; let i = index" [removable]="true" (removed)="onRemove(i, tag)" [formGroupName]="i">
                {{tag.get('Text').value}}
        <mat-icon matChipRemove>cancel</mat-icon>
      </mat-chip>
      <!-- Use below if only having single formcontrol -->
      <!-- <mat-chip *ngFor="let tag of tagsArr.controls; let i = index" [removable]="true" (removed)="onRemove(i)">
                {{tag.value}}
        <mat-icon matChipRemove>cancel</mat-icon>
      </mat-chip> -->
    </mat-chip-list>
  </mat-form-field>

  <mat-chip-list>
    <mat-chip *ngFor="let tag of tags" [selectable]="selectable" (click)="onSelect(tag)">
    {{tag.Text}}
    </mat-chip>
    </mat-chip-list>
    <button type="submit">Submit</button>
    </form>

TS file:

 registerForm: FormGroup;


selected = [];

  tags = [{ Text: 'one' }, { Text: 'two' }];

  constructor(private fb: FormBuilder) {
    this.registerForm = this.fb.group({
      Tags: this.fb.array([]),
    });
  }

  get tagsArr() {
    return this.registerForm.get('Tags') as FormArray;
  }

  onSelect(tag: any) {
    this.tagsArr.push(
      this.fb.group({
        Text: tag.Text,
      })
    );
    this.tags.splice(this.tags.indexOf(tag), 1);
  }

  onRemove(index, tag): void {
    this.tagsArr.removeAt(index);
    this.tags.push(tag.value);
  }

  onSubmit(){
    console.log(this.registerForm.value)
  }
}

CodePudding user response:

Here is how you could implement a chip input with autocomplete

HTML:

  <form [formGroup]="myForm">
    <mat-form-field>
      <mat-label translate>Tags</mat-label>
      <mat-chip-list #chipList>
        <mat-chip *ngFor="let tag of tags" (removed)="remove(tag)" color="accent">
          {{tag}}
          <button matChipRemove>
            <mat-icon>cancel</mat-icon>
          </button>
        </mat-chip>
        <input placeholder="New tag ..." #tagInput
          [formControl]="tagControl"
          [matAutocomplete]="auto"
          [matChipInputFor]="chipList"
          (matChipInputTokenEnd)="add($event)"
          matChipInputAddOnBlur>
      </mat-chip-list>
      <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
        <mat-option *ngFor="let tag of filteredTags | async" [value]="tag">
          {{tag}}
        </mat-option>
      </mat-autocomplete>
    </mat-form-field>
  </form>

TS:

  myForm: FormGroup
  filteredTags: Observable<string[]>
  allTags: string[] = []
  tags: string[] = []

  @ViewChild('tagInput') tagInput: ElementRef<HTMLInputElement> | undefined = undefined

  constructor(
    private fb: FormBuilder
  ) {
    this.myForm= this.fb.group({
      tags: ['']
    })

    this.filteredTags = this.tagControl.valueChanges.pipe(
      startWith(null),
      map(tag => tag ? this.filter(tag): this.allTags.slice())
    )
  }

  ngOnInit(): void {
    this.allTags = ['concert', 'restaurant', 'pub']
  }

  // TAG AUTOCOMPLETE CONTROL
  get tagControl(): FormControl {
    return this.myForm.get('tags') as FormControl
  }

  remove(tag: string): void {
    const index = this.tags.indexOf(tag)

    if (index >= 0) {
      this.tags.splice(index, 1)
    }
  }

  add(event: MatChipInputEvent): void {
    const value = (event.value || '').trim()
    if (value) {
      this.tags.push(value)
    }

    event.chipInput?.clear()
    this.tagControl.setValue(null)
  }

  selected(event: MatAutocompleteSelectedEvent): void {
    this.tags.push(event.option.viewValue)
    if (this.tagInput) {
      this.tagInput.nativeElement.value = ''
    }
    this.tagControl.setValue(null)
  }

  private filter(value: string): string[] {
    const filterValue = value.toLowerCase()

    return this.allTags.filter(tag => tag.toLowerCase().includes(filterValue))
  }
  • Related