In angular, mat-autocomplete won't close on click outside when opened in mat-dialog

486 Views Asked by At

I am working with form inside mat-dialog and i have problem with closing mat-autocomplete dropdown when clicked outside. I have mat-select implemented the sam way and he is working properly.

Here is my implementation for both elements

Autocomplete

      <mat-form-field
        appearance="outline"
        floatLabel="always">
        <mat-label class="input-label">{{ input.label }}</mat-label>
        <input
          matInput
          [type]="input.inputType"
          [name]="input.name"
          [placeholder]="input.placeholder"
          [id]="input.id"
          [readonly]="input.readOnlyOnAction.includes(formAction)"
          [formControlName]="input.controlName"
          [matAutocomplete]="auto" />
        <mat-autocomplete #auto="matAutocomplete">
          <mat-option
            *ngFor="let item of input.filteredData"
            [value]="item[input.dataValue]">
            {{ item[input.dataLabel] }}
          </mat-option>
        </mat-autocomplete>
      </mat-form-field>

Select

      <mat-form-field
        appearance="outline"
        floatLabel="always">
        <app-svm-svg-icon-hover-rotate
          matSuffix
          svgIcon="chevron"
          [rotate]="false"
          [rotateAngle]="180"
          iconStroke="#0069B4"
          [rotate]="select.panelOpen"
          [rotateAngle]="180"
          (click)="select.panelOpen ? select.close() : select.open()">
        </app-svm-svg-icon-hover-rotate>
        <mat-label class="input-label">{{ input.label }}</mat-label>
        <mat-select
          matNativeControl
          [placeholder]="input.placeholder"
          [id]="input.id"
          [formControlName]="input.controlName"
          #select>
          <ng-container *ngIf="input.data?.length > 0; else noData">
            <mat-option
              *ngFor="let item of input?.data"
              [value]="item[input.dataValue]">
              {{ item[input.dataLabel] }}
            </mat-option>
          </ng-container>
          <ng-template #noData>
            <mat-option> No Data </mat-option>
          </ng-template>
        </mat-select>
      </mat-form-field>
1

There are 1 best solutions below

0
Ismail Hachimi On

Here is a simple solution to your problem.

import { fromEvent, Subscription } from "rxjs";
import {
  Component,
  OnDestroy,
  ViewChild,
  Input,
} from "@angular/core";
import { MatAutocompleteTrigger } from "@angular/material/autocomplete";

@Component({
  selector: "input",
  template: `
    <mat-form-field appearance="outline" floatLabel="always">
      <mat-label class="input-label">{{ input.label }}</mat-label>
      <input
        matInput
        #inputRef
        [type]="input.type"
        [name]="input.name"
        [placeholder]="input.placeholder"
        [id]="input.id"
        [readonly]="input.readOnlyOnAction.includes(formAction)"
        [formControlName]="input.controlName"
        [matAutocomplete]="auto"
      />
      <mat-autocomplete #auto="matAutocomplete">
        <mat-option
          *ngFor="let item of input.filteredData"
          [value]="item[input.dataValue]"
        >
          {{ item[input.dataLabel] }}
        </mat-option>
      </mat-autocomplete>
    </mat-form-field>
  `,
  styleUrls: ["./input.component.scss"],
})
export class InputComponent implements OnDestroy {
  @Input() input: any; // your input data

  // ref to the autocomplete trigger
  @ViewChild("inputRef", { read: MatAutocompleteTrigger })
  autocompleteTrigger!: MatAutocompleteTrigger;

  private outsideClickSubscription!: Subscription;

  openAutocompletePanel() {
    this.outsideClickSubscription = fromEvent<MouseEvent>(document, "click", {
      capture: true,
    }).subscribe(() => {
      this.closeAutocompletePanel();
    });
  }

  closeAutocompletePanel() {
    this.autocompleteTrigger?.closePanel();
    this.outsideClickSubscription?.unsubscribe();
  }

  ngOnDestroy() {
    this.outsideClickSubscription?.unsubscribe();
  }
}

This solution is basic and simple, and captures any click in the document and unsubscribes to outsideClick subscription. It can be improved if needed.