Components: autocompletes overlay position works wrong on mobile devices

Created on 8 Aug 2017  Â·  59Comments  Â·  Source: angular/components

Bug, feature request, or proposal:

Bug

What is the expected behavior?

Correct overlay position so that the component can be used on mobile devices

What is the current behavior?

On mobile devices (e.g iphone6+ with latest IOS, Android etc.) the position of the overlay is strange.
Sometimes the overlay disappears or the overlay overlaps the input fields ...

So autocomplete is NOT usable on mobile devices....

What are the steps to reproduce?

E.g. use the https://material.angular.io/ demo for autocomplete on mobile devices

What is the use-case or motivation for changing an existing behavior?

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular 4.3.3, Material 2.0.0-beta.8

Is there anything else we should know?

P3 has pr

Most helpful comment

For anyone still following this thread, hoping for a fix, I got tired of waiting for one and just scrapped the autocomplete from our project entirely and built my own component that looks identical but actually works, for all browsers and all platforms.

The idea is this:

HTML

<div>
    <mat-input-container class="//whatever class you have to make this the right width">
        <input #itemFilterInput matInput type="text" placeholder="ITEM" (click)="showItems = true">
    </mat-input-container>
    <mat-card [hidden]="!showItems" class="autocomplete">
        <mat-option *ngFor="let item of items" [value]="item.name" (click)="selectItem(item)">
            {{ item.name }}
        </mat-option>
    </mat-card>
</div>

TS

showItems: boolean = false;
@ViewChild('itemFilterInput') itemFilterInput: ElementRef;

ngOnInit() {
    Observable.fromEvent(this.itemFilterInput.nativeElement, 'keyup')
        .debounceTime(300)
        .distinctUntilChanged()
        .subscribe(() => {
            this.items = [];
            if (this.itemFilterInput.nativeElement.value && this.itemFilterInput.nativeElement.value.length > 1) 
            {
               this.itemService.getItemsBySearch(this.itemFilterInput.nativeElement.value).subscribe(items => {
               this.items = items;
               this.showItems = true;
            });
        }
    });
}

selectItem(item) {
    this.itemFilterInput.nativeElement.value = item.name;
    this.showItems = false;
}

CSS

.autocomplete {
    max-height: 150px; 
    overflow:auto; 
    position: fixed !important; 
    padding: 0 !important;
    z-index:1000;
}

All 59 comments

The positioning of the autocomplete just changed to be more accurately connected to the input. Here is an example with the latest build: http://plnkr.co/edit/HnQwfr7WlNVLdP3P6ukQ?p=preview

However, I am still seeing some weird positioning in landscape mode with the keyboard open:

img_4975

The issue is that the keyboard animation throws off the positioning logic. I've been considering whether having a setTimeout on focus for iOS and Android would make sense @jelbourn?

@crisbeto that seems reasonable if we scope the delay to only apply for these cases. Let's address this after the overlay positioning refactor

@crisbeto is there any timeframe until func is getting better on IOS -> Otherwise I have to consider to replace autocomplete temporarly...

The initial plan was to address this after we refactor some of our positioning logic, but I suppose that shouldn't really change what we do in the autocomplete. There should be a way for you to patch it on your side temporarily, but it'll be very hacky, because it would need to access private properties on the autocomplete trigger.

@crisbeto what is the way to "patch" autocomplete so that it work better on IOS???

I've been playing around with the approach I mentioned above, but it doesn't really work the way I expected it to. It seems like the autocomplete does figure out the proper position values, however iOS throws it off when it scrolls the input into the middle of the view. Delaying the positioning call doesn't help in this case.

@crisbeto Is there a solution to this problem? What is the recommended way to go?

Any update on this issue?

@crisbeto, @maku is there any workaround or patch for this issue?

This is somewhat tricky to fix on our end, because iOS seems to shift the coordinate grid when it focuses the into view, which makes it so we can't recalculate the position correctly. The best approach for now might be to disable scrolling for the autocomplete altogether. See https://github.com/angular/material2/issues/5187#issuecomment-324371834.

@crisbeto dump question - how do other ui libraries handle this problem?

The easiest way to handle it would be to use position: absolute to position the panel, however that is problematic when dealing with focus and overflow.

@crisbeto I would really appreciate an advice what to do... - should we drop using autocomplete?? and looking for an alternative (also the fix #5187 does not work for me)
Is there anything in the pipeline? The component as it is is NOT usable on IOS.

Just to be curious - what problems does material2 have what other libs don't have (so that this stuff works on IOS)?

@crisbeto I really do not want to be annoying. But is there any kind of solution on the horizon?

Any updates? using latest and issue with iOS positioning as well as touch. I can not select an item from autoComplete component. I'm using the code from your example to test. I have hammer js installed the toggle button works and requires hammer js as per your spec. Not sure why I can not select an item but positioning is still an issue. Thanks!

This very issue is causing headaches on my side too.

The following two suggestions have helped the situation and make the autocomplete somewhat usable on iOS:

  1. Add cdkScrollable to your
    @crisbeto, #4557)
  2. Add custom scrolling strategy (@aitboudad, #5187)

We have a related issue, maybe it's the same.

For us, the dropdown list gets hidden entirely by the keyboard, instead of the dropdown list going upwards (the autosuggest field is in the middle of the page).

https://imgur.com/a/nrBUw

Any updates on this issue?! I'm facing the same problem!!

Just want to add my thoughts on this. As I am facing this issue as well. Not sure if any of this information will help, but figured to add some notes here.

When testing on an iPad in debug mode connected to a MacBook, I noticed that when highlighting the AutoCompletePanel in the HTML element in the debugger, it does highlight the element, and the highlight is shown directly underneath the input field. So the positioning of the css is correct.

But the kicker is that the browser is rendering the auto complete panel NOT where the highlighted HTML is. Which leads me to believe that it is something with how iOS Safari is rendering the HTML elements while the keyboard is up.

This is just a comment supporting @crisbeto comment regaring iOS shifting it's coordinate grid.

For anyone still following this thread, hoping for a fix, I got tired of waiting for one and just scrapped the autocomplete from our project entirely and built my own component that looks identical but actually works, for all browsers and all platforms.

The idea is this:

HTML

<div>
    <mat-input-container class="//whatever class you have to make this the right width">
        <input #itemFilterInput matInput type="text" placeholder="ITEM" (click)="showItems = true">
    </mat-input-container>
    <mat-card [hidden]="!showItems" class="autocomplete">
        <mat-option *ngFor="let item of items" [value]="item.name" (click)="selectItem(item)">
            {{ item.name }}
        </mat-option>
    </mat-card>
</div>

TS

showItems: boolean = false;
@ViewChild('itemFilterInput') itemFilterInput: ElementRef;

ngOnInit() {
    Observable.fromEvent(this.itemFilterInput.nativeElement, 'keyup')
        .debounceTime(300)
        .distinctUntilChanged()
        .subscribe(() => {
            this.items = [];
            if (this.itemFilterInput.nativeElement.value && this.itemFilterInput.nativeElement.value.length > 1) 
            {
               this.itemService.getItemsBySearch(this.itemFilterInput.nativeElement.value).subscribe(items => {
               this.items = items;
               this.showItems = true;
            });
        }
    });
}

selectItem(item) {
    this.itemFilterInput.nativeElement.value = item.name;
    this.showItems = false;
}

CSS

.autocomplete {
    max-height: 150px; 
    overflow:auto; 
    position: fixed !important; 
    padding: 0 !important;
    z-index:1000;
}

Came to same approach as @stevenmcountryman. Created autocomplete by myself because MatAutocomplete is not usable on mobile at all.

Friendly ping please. I'm using this on an email field so I can't create my own autocomplete.

We ran into the same issue.

Any idea if we shall wait for a fix or start writing our own autocomplete component ?

I have same problem after testing it on iOS autocomplete is not working same way as on Android

I would say that on website it should say anything about this problem because currently it seems that autocomplete is not production ready.

Well a bit of frustration in this topic. I dont understand why this issue is not critical, its not that something is not perfect issue is that it just dont work. What the reason to improve if one of the features are not working. And again lib is production ready without any notes that its not working. I would understand if issue is on windows phone because nobody care but IPhone has huge audience....
Btw vue autocomplete is working 🥇

For people who is looking for replacement http://leaverou.github.io/awesomplete. Seems to be easy to integrate.

@vovikdrg i understand you, and agree about note on main site, but that lib is still in beta so we have what we have...
Maybe it is possible to try some "simple" fix which will allow to position dropdown with styles, without fancy js resizing and jumping below and above?

@sava1192 what do you mean it still in beta? its marked as stable for few month

@vovikdrg ohh, i missed it:) but problem remains :)

Just tried to implement today the autocomplete module and I'm experimenting the same issue. I hope this will be solved.

Hello Material Team.

I have been looking around trying to find where the logic may be, but I have been unsuccessful.

It seems like the overlay doesn't respect the new screen size when the keyboard is opened.

However, it's initial position, after keyboard is opened may be correct... but after you begin scrolling (while keyboard is open)... It looks like the panel's positioning is based on the screensize before the keyboard was opened.

I hope this helps..

This is a critical bug in our backlog right now, So if no one is able to complete this soon, maybe someone can point me in the right direction and I can make the fix.

Hi @joelcoxokc

I believe this bug, it is not a screen size problem
because after virtual keyboard opened screen coordinate (point 0,0) will be pushed outside of the screen
You can verify it by adding an element with position fixed and top = 0
please refer to this comment

this is a wrong behavior and it is a safari bug
so the actual solution should be provided by safari team
as iPhone is popular we need a good and stable workaround, or we should ignore benefit s of positioning the overlay(which will work) please refer to this comment

Actually wondering what material 2 is good for...

the layout is not usable so I had to switch to bootstrap 2.

the more we are trying to use some of the widget the more bug are appearing.

quite a disapointment

@mahmood-sajjadi Thank you.

@anymos This isn't really the place to put comments about the library as a whole.
If you are looking for a library to do a lot more Layout customization, try using https://teradata.github.io/covalent/#/.
It is built on top of Angular/Material.

@joelcoxokc main problem with covalent is that it inherits all bugs from material...

For now, our solution is using a full-screen dialog. with a search bar at the top, and a repeated list, filtered by the search value takes up the rest of the screen.

It is pretty simple to do, and doesn’t require any positioning.

Until this bug is fixed.

Just make sure you add the proper scrolling css properties for iOS

This is a really bad problem for me too. Any word on when we can get a fix?

No solution (fix or patch) for now ? This issue is 9 months old

+1 would like to see a fix for this also.

A full screen dialog with a list and search box at the top is the simplest
solution for now.
On Fri, Mar 30, 2018 at 6:54 PM Edwin Popham notifications@github.com
wrote:

+1 would like to see a fix for this also.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/angular/material2/issues/6341#issuecomment-377648237,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AEc7HDfeJ4JWpx7HEwXJzD46JgUZoCkVks5tjsW6gaJpZM4OwR6o
.

I don’t want to use another dependency. My whole webapp is based on material. I can wait for a patch but i’m very surprised that kind of behavior tooks more than 9 months to be fixed.

@MikaStark good for you in my case I didn't have choice. I must support mobile..

After 1 month, here is a little up 🙂

https://www.w3schools.com/tags/tag_datalist.asp

Guys use HTML 5 Datalist, its working awesome

@waseemshaz, looks like that isn't supported by Safari at all which makes it a no go

Is it possible just to add a search field to the select? I think that is
why most people want autocomplete in the first place.

We just created our own custom component that puts an input inside the
mat-select-content
On Sat, May 5, 2018 at 5:08 PM stevenmcountryman notifications@github.com
wrote:

@waseemshaz https://github.com/waseemshaz, looks like that isn't
supported by Safari at all which makes it a no go

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/angular/material2/issues/6341#issuecomment-386838467,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AEc7HLtB4g6hRurb_iXuKZCuvjHq450dks5tviLTgaJpZM4OwR6o
.

June has come and no fix even after couple of material updates

No news about this one?

Nope 😤 still P3 but no one cares 🤪

waitet for fix for so long, that switched to React already

See the explanation in #11946 where (i think) the problem is in the code (my issue is unrelated to mdAutocomplete, but also involves the iOS keyboard).

So aside from the PR, i also added a workaround to my custom component. The code below works for me on iOS: the overlay is positioned correctly when scrolling with the keyboard visible:

    this.overlayDir.positionChange.subscribe((position: ConnectedOverlayPositionChange) => {
      const clientRect = this.overlayDir.overlayRef.hostElement.getBoundingClientRect();

      if (clientRect.top !== 0) {
        const overlayElement = this.overlayDir.overlayRef.overlayElement,
              overlayY = position.connectionPair.overlayY;

        if (overlayY === 'top') {
          const top = parseInt(overlayElement.style.top);

          overlayElement.style.top = top + Math.abs(clientRect.top) + 'px';
        } else if (overlayY === 'bottom') {
          const bottom = parseInt(overlayElement.style.bottom);

          if (bottom >= Math.abs(clientRect.top)) {
            overlayElement.style.bottom = bottom + clientRect.top + 'px';
          }
        }
      }
    });

@jpzwarte your workaround seems to work perfectly - thanks. My overlays now position correctly when the iOS keyboard is out.

@jpzwarte I don't understand your solution. How does one get a reference to overlayDir? Do you have a more complete example?

@geoFlux you can get it using a ViewChild on your cdkConnectedOverlay directive:

<ng-template #connectedOverlay="cdkConnectedOverlay" cdkConnectedOverlay></ng-template>

And then in your component:

  @ViewChild("connectedOverlay") private _connectedOverlay: CdkConnectedOverlay;

@jinder I was not able to make it work with sample provided. Do you mind sharing plunker, please?

@stevenmcountryman : Thanks for your solution provided here: https://github.com/angular/material2/issues/6341#issuecomment-348549272. I've applied same solution in my project. This resolve issue of showing list options at correct position but getting issue with selecting option by clicking function "selectItem(item)". Issue here is, selectItem function fires on 2nd time click. It doesn't fire on first time click. Any idea how to solve this issue? It would be really great help if you can help to sort out this issue.

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alanpurple picture alanpurple  Â·  3Comments

MurhafSousli picture MurhafSousli  Â·  3Comments

Hiblton picture Hiblton  Â·  3Comments

Miiekeee picture Miiekeee  Â·  3Comments

RoxKilly picture RoxKilly  Â·  3Comments