mat-autocomplete options dropdown does not stick when scrolling
Asked Answered
C

4

13

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.

Congest answered 25/2, 2020 at 15:54 Comment(1)
I have the same issue and the answer bellow didn't work for meCortes
C
19

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>
Congest answered 25/2, 2020 at 15:54 Comment(5)
You need cdkScrollable on element which has scroll.Gower
for some reason it didn't work for me. It would be helpful to have a stackbliz exampleCortes
Pls note 2nd point outermost div.....Rural
What If my scroll is set by ion-content? Then how can i use cdkScrollable. It doesn't work with that. Please help.Mercer
Thanks! It worked for me without explicitly importing ScollingModule (maybe a submodule of another one?) in Angular 17.2.x.Unwritten
K
9

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

Kozak answered 27/1, 2021 at 7:5 Comment(4)
this.scrollEvent? Property 'scrollEvent' does not exist on type 'XComponent'.Cortes
I feel you having XComponent, and you either missed to declare the scrollEvent function or function name mismatch.Kozak
You may share your problem by creating example on stackblitz, I can help you. @RoyerAdamesKozak
I appreciate you Abhishek Kumar. In the end, I got it solved by disabling the scrolling with a div that has 100vh and 100vwCortes
E
4

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" />
Empanel answered 15/12, 2021 at 7:30 Comment(2)
works but it has the feature of the options not hiding with the rest of the other content when scrollingCortes
Yes, it may added with updates to angular material. I think I need to update the answer to match with latest versions.Empanel
P
0

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>
Pinup answered 4/11, 2020 at 14:55 Comment(1)
Property 'document' does not exist on type 'Component'.Cortes

© 2022 - 2024 — McMap. All rights reserved.