Material-components-web: Slider keeps following touches while scrolling on mobile devices

Created on 26 Aug 2017  路  6Comments  路  Source: material-components/material-components-web

After sliding, the sliders keep actively tracking the touches until you give the document a single tap.

Tested in Chrome for Android and OSX
slider demo

backlog bug

All 6 comments

Good catch; I was able to reproduce this in Chrome on Android, and on desktop using device emulation.

Worth noting, this only seems to happen when you actually drag to slide the control; if you simply tap the control, it doesn't seem to happen.

The PR filed against this (#1214) seems to suggest that we may be leaking event handlers, or hooking up too many to begin with. This is further corroborated by adding logging statements to downHandler, moveHandler, and upHandler.

On Chrome desktop with device emulation, I get the following behaviors...

When tapping (no bug):

  • downHandler (pointerdown)
  • downHandler (touchstart)
  • upHandler (pointerup)
  • upHandler (touchend)
  • downHandler (mousedown)
  • upHandler (mouseup)

When dragging (bug):

  • downHandler (pointerdown)
  • downHandler (touchstart)
  • moveHandler (pointermove)
  • ...
  • moveHandler (touchmove)
  • ...
  • upHandler (touchend)

For some reason, no pointerup event ever gets handled, so we end up with a leaked handler. This is odd, since in Chrome on desktop without emulating mobile, both mouse and pointer events occur consistently.

Moreover, while I can reproduce this on Chrome on Android, I couldn't reproduce it on Firefox on Android, and Alex wasn't able to reproduce it on Safari on iOS either.

I'm wondering at this point if this is a bug specific to Chrome on Android. However, I think we might be able to avoid the issue if we store an instance property to manage these handlers when active is first set, and avoid hooking up more than one set of handlers at a time? I'm open to thoughts on this.

@kfranqueiro thanks for the help with the PR!

I looked deeper and I noticed that downHandler is only deregistered in destroy event. So whenever body receives a touchstart, downHandler gets called, which registers moveHandler and upHandler again. So I don't see a reason this.setActive_(false); would stop moveHandler from firing. Am I missing something?

The handlers for move and up events are registered within the down handler, and deregistered within the up handler immediately after setActive_(false) is called. When the up handlers are fired in a 1-to-1 relationship with the down handler, active_ is maintained in parallel with the lifetime of the move/up handlers, and there's no issue.

Also, to clarify, the down handler is only registered on the root element of the slider component (using registerInteractionHandler, not registerBodyInteractionHandler). The move and up handlers, however, are registered on the body, which is why it's important they only be registered while the slider is being interacted with.

Is there any fix that can be done to work around this issue?
I have a page with multiple sliders ad this makes it unusable in mobile.

@porfirioribeiro I'm using this to work around this issue:

if (!this.active_) {
    return;
}

inserted before this line

Remembering it's not a good solution, just a temporary work around.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

robzenn92 picture robzenn92  路  4Comments

CyborgSemon picture CyborgSemon  路  3Comments

ghost picture ghost  路  3Comments

abhiomkar picture abhiomkar  路  3Comments

jimyhdolores picture jimyhdolores  路  3Comments