Prevent touchmove default on parent but not child

47,167

Solution 1

Try this:

$('#fix').on('touchmove',function(e){
    if(!$('.scroll').has($(e.target)).length)
        e.preventDefault();
});

EDITED

e.target contains the final target node of the touch event. You can stop all events that are not "bubbling accross" your .scroll divs.

I think there are better solutions, but this one must be ok.

Solution 2

document.addEventListener('touchmove', function(e){e.preventDefault()}, false);
document.getElementById('inner-scroll').addEventListener('touchmove', function(e){e.stopPropagation()}, false);

The idea is that your main scroll is always (to your discretion) disabled, but in your inner-scroll you prevent the event from bubbling up (or propagating), so it will never reach the first event listener, which would ultimately cancel the touchmove event.

I hope this is what you were looking for. I've had a situation similar to yours, where the main scroll was disabled on tablet, but i wanted an inner scroll to work. This seemed to do the job.

Solution 3

This should work:

$(document).on('touchmove', function(e) {
    if (!$(e.target).parents('.scroll')[0]) {
        e.preventDefault();
    }
});

Solution 4

I found an interesting discussion here: https://github.com/joelambert/ScrollFix/issues/2 , and there's a good solution from bjrn

Basically, it takes advantage of flex boxes. Worked well for me on ipad. Here is a test link he set up that shows it at work: http://rixman.net/demo/scroll/

What's especially nice about this solution is that it's all CSS and no javascript required.

Solution 5

I found another solution using css-classes and document.ontouchmove. I'm developing an IPad Webapp with Sliders and wanted to prevent all the other elements to bounce when there's a touchmove event. This is my solution as an abstract:

HTML:

<body>
  <div id="outterFrame" class="fullscreen"> <!-- class fullscreen is self-explaining I guess -->
      <div id="touchmove_enabled class="enable_touchmove sliderbutton">Button</div>
  </div>
</body>

Javascript:

/* preventDefault on touchmove events per default */
document.ontouchmove = function(event)
{
   var sourceElement = event.target || event.srcElement;
   if(!hasClass(sourceElement,"enable_touchmove"))
{
   e.preventDefault();
}
};

/* helper method "hasClass" */
function hasClass(element,class)
{
if(element.className != null)
{
    return element.className.match(new RegExp('(\\s|^)'+class+'(\\s|$)'));
}
return false;
}

Now, only the touchmove event of the div "touchmove_enabled" is fired.

Probably my solution may be useful for somebody. Patric

Share:
47,167
will
Author by

will

I work for Engage

Updated on August 03, 2022

Comments

  • will
    will almost 2 years

    I am creating a little web app for the iPad and I've got several elements I am preventing the user from scrolling by preventing default on the touchmove event. However, I have a situation where I need the user to be able to scroll a child element.

    I have tried to use e.stopPropagation(); but no luck! I also attempted to detect the element under the finger and put the e.preventDefault(); inside an if statement, but again, no luck. Or maybe I was just getting mixed up...

    Any ideas? Removing the .scroll divs from the #fix div is a last resort really as it will cause all sorts of headaches.


    EDIT

    I managed to sort it. Seems like I didn't understand the use of .stopPropagation(); oops!

    The working code:

    <div id="fix">
    
        <h1>Hi there</h1>
    
        <div class="scroll">
            <ul>
                <li>List item</li>
                <li>List item</li>
                <li>List item</li>
            </ul>
        </div>
    
        <div class="scroll">
            <ul>
                <li>List item</li>
                <li>List item</li>
                <li>List item</li>
            </ul>
        </div>
    
    </div>
    

    And the Javascript:

    $('body').delegate('#fix','touchmove',function(e){
    
        e.preventDefault();
    
    }).delegate('.scroll','touchmove',function(e){
    
        e.stopPropagation();
    
    });