Francesco Borzi
Francesco Borzi

Reputation: 61724

mat-autocomplete options dropdown does not stick when scrolling

In my Angular app, I'm using the autocomplete feature from Angular Material:

angular material autocomplete

It works fine, except when I scroll the page:

angular material autocomplete scrolling issue

Basically the dropdown does not stick in its position when scrolling and I can't figure out why.

In the official Material documentation page, it works well by automatically updating the top and left properties of the element. However, this does not happen in my app.

Upvotes: 13

Views: 18312

Answers (4)

Janith Widarshana
Janith Widarshana

Reputation: 3483

Following solution works for me. Hope this will be a help to someone.

I added AutocompletePositionModule module. Then added directive and used in many places in my project.

Module file

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AutocompletePositionDirective } from './autocomplete-position.directive';
import { MatAutocompleteModule } from '@angular/material/autocomplete';

    @NgModule({
      declarations: [
        AutocompletePositionDirective
      ],
      exports: [
        AutocompletePositionDirective
      ],
      imports: [
        CommonModule,
        MatAutocompleteModule,
    
      ]
    })
    export class AutocompletePositionModule { }

Directive file

import { Directive, Input, OnDestroy } from '@angular/core';
import { MatAutocompleteTrigger } from '@angular/material/autocomplete';

@Directive({
  selector: '[appAutocompletePosition]',
  exportAs : 'appAutocompletePosition'
})
export class AutocompletePositionDirective implements OnDestroy {
  public constructor(
    private readonly matAutocompleteTrigger: MatAutocompleteTrigger,
  ) {
    window.addEventListener('scroll', this.scrollEvent, true);
  }

  public ngOnDestroy(): void {
    window.removeEventListener('scroll', this.scrollEvent, true);
  }

  private scrollEvent = (): void => {
    if (this.matAutocompleteTrigger == null) {
      return;
    }
    if (this.matAutocompleteTrigger.panelOpen) {
      this.matAutocompleteTrigger.updatePosition();
    }
  }
}

Usage

<input type="text" matInput [matAutocomplete]="auto" #trigger="matAutocompleteTrigger" appAutocompletePosition="trigger" />

Upvotes: 4

Abhishek Kumar
Abhishek Kumar

Reputation: 1040

First of all we need to be able to use autoComplete methods, so we must take this control from the view. Add the id: #autoCompleteInput

     <input
        #autoCompleteInput
        type="text"
        class="form-control"
        matInput
        [matAutocomplete]="auto"
        formControlName="country"
        (input)="filterCountries($event.target.value)"
      />

In the component:

@ViewChild('autoCompleteInput', { read: MatAutocompleteTrigger })
  autoComplete: MatAutocompleteTrigger;

Now we have autoComplete as a variable. Next we need a scrolling event:

ngOnInit(): void {
    window.addEventListener('scroll', this.scrollEvent, true);
}

And finally add a function to the component:

scrollEvent = (event: any): void => {
    if(this.autoComplete.panelOpen)
      // this.autoComplete.closePanel();
      this.autoComplete.updatePosition();
};

Ref: Origin

Upvotes: 9

Youssef Gahouchi
Youssef Gahouchi

Reputation: 1

My mat-autocomplete is located in mat-dialog, importing ScrollingModule and adding cdkScrollable to my div, didn't seem to help, so I managed to hide the list when scrolling, because when scrolling the list of options isn't really important.

I used:

removeAutocompleteFocus() {
    let element = this.document.querySelector('.mat-autocomplete-panel');
    if (element) {
    element.parentNode.removeChild(element);
    }
  }
<div (scroll)="removeAutocompleteFocus()"></div>

Upvotes: 0

Francesco Borzi
Francesco Borzi

Reputation: 61724

After doing some research, I've found a solution posted by omaracrystal on github.

What I needed to do is to:

1) Import the ScrollingModule of the Angular CDK

import { ScrollingModule } from '@angular/cdk/scrolling';

@NgModule({
  imports: [
    // ...
    ScrollingModule,
  ],
  // ...
})
export class MyAppModule { }

2) Find the outermost div that contains my autocomplete input and apply the cdkScrollable directive:

<div cdkScrollable>
  <!-- the autocomplete is located somewhere here, not necessarily as direct child -->
</div>

Upvotes: 19

Related Questions