Prevent touchmove default on parent but not child

disable touch scroll css
touchmove preventdefault
touchmove event
jquery touchmove
treat document level touch event listeners as passive
angular touchmove preventdefault
javascript cancel touch event

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();

});

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.

Prevent body scrolling when the user scrolls on fixed position div , I would like to prevent scrolling through the fixed element, but I would like to allow You'd need some JS for that – disabling default scrolling : Indeed it is, any element that receives a touchmove inside body will trigger momentum scrolling as long as that element's parent does not have any overflow itself. You want to prevent the default on the touch move event however you also need to clear your flag for this at the end of the touch event otherwise no touch scroll events will work. This can be accomplished without jQuery however for my usage, I already had jQuery and didn't need to code something up to find whether the element has a particular

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.

touchstart preventDefault() does not prevent click event. � Issue , preventDefault() on a synthetic onTouchStart event fails to prevent the click (the new default) and that passive event listeners do not allow calling and implement double handlers on both a parent and a child, the child's e. It would be nice if we had something better. My esteemed colleague, Tom suggested making use of touchstart to prevent the default scroll behaviour and while that solved the initial problem (being able to scroll past the modal) it prevented clicks inside the modal. But it wasn’t long before that approach led us to using touchmove instead.

This should work:

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

willmcpo/body-scroll-lock, GitHub is home to over 50 million developers working together to host and Specifically, the target element is the one we would like to allow scroll on (NOT a parent of To disable scrolling on iOS, disableBodyScroll prevents touchmove events. on an element, but its children still require touchmove events to function. I think it had to do with touch-action: manipulation but I am yet to confirm) This is important to us because we use event.preventDefault() on a touchmove event to prevent native scrolling on mobile. I can Work around: You need to add an event handler in a non dynamic way (ie at startup) and then you can use event.preventDefault() as expected.

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.

Handling Events :: Eloquent JavaScript, A program can then periodically check the queue for new events and react to what it finds there. When it is moved while touching, "touchmove" events fire. A handler on a parent element is not notified when a child element gains or loses focus. If you prevent the default behavior on this event and set the returnValue � Without the stopPropagation, the parent ondragstart will still be called even if the default behavior will be prevented (event.defaultPrevented == true). If you have code in that handler that doesn't handle this case, you may see subtle bugs.

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

Event Handling - Enyo Developer Guide, In general, events bubble up the component tree from child to parent. This function takes an optional event parameter, which must be an object and can If you need to control the default action on a DOM event, use the modern equivalent, event. stopPropagation() will not prevent propagation of events in Enyo; instead,� In that case I suspect scrolling the element will indeed not work when this code is used. Not because it is inside body but for the reason that all touchmove behaviour has been disabled. Then again, if it has overflow then swiping it will not bubble up and cause momentum page scrolling but ‘normal and local’ scrolling on the element.

Create a Draggable Element in JavaScript, addEventListener("touchmove", drag, false); container. When that happens, your drag will abruptly stop. No matter how quickly you are dragging your element around, you will almost always be The repositioning logic deals with the parent element, and the rotation deals with the child image element. A common scenario with nested components is the desire to run a parent component's method when a child component event occurs. An onclick event occurring in the child component is a common use case. To expose events across components, use an EventCallback. A parent component can assign a callback method to a child component's EventCallback.

Drag and Drop It Like It's Hot: Setting Up the Ultimate Gestures , The touchstart and touchmove events provide a list of finger contacts with the screen in To avoid that, set the default value for both variables to 0. The current element does not take physical space inside its parent anymore. to the . drop-area, it will behave as if it were one of the children of .drop-area. However, parents must not stop or interfere with the other parent's rights or responsibilities under the parenting order. The court only considers making orders that the children do not see one parent in special circumstances, such as where the court considers the child to be at serious risk of harm.

Event Bubbling, There are two ways of event propagation in DOM i.e. Event (might not be the case always but let's just agree; the bubbles always rise preventDefault() which prevents the browser from executing the default action of the� The parent not in possession of the child on the child’s birthday is entitled to pick up the child for two hours between 6 p.m. and 8 p.m. Summer If the parents live within 100 miles of each other, the noncustodial parent is entitled to 30 days of parenting time during the summer months.

Comments
  • Try Adding return false; at the end of event handler
  • write stopPropagation instead of stopPropogation
  • Ha, yea, thankfully I was actually typing it correctly in my code ;)
  • You should add your solution as an answer and accept, it worked for me. Thank you!
  • I'm confused, how exactly did you solve the problem? Can you please point out which is the working code, for numbskulls like me? haha thanks :)
  • Best solution I've seen yet. +1
  • The subject specifies the parent, not the element itself, so use of closest() would not be correct.
  • A cleaner way to write that is: $(document).on("touchmove", function(e) { e.preventDefault() }); $(document).on("touchmove", ".scroll", function(e) { e.stopPropagation() });
  • That will disable touchmove across the whole document. You also don't need to reference $(document) twice if you chain the functions.