101

I'm using Framework7 sortable list and it works well, just that it doesn't trigger an event when the list is changed.

So I'm trying a few built-in events:

$('.sortable-handler').on('touchstart', function (e) {
    e.preventDefault();
    alert('touchstart');
});

$('.sortable-handler').on('touchmove', function (e) {
    e.preventDefault();
    console.log('touchmove');
});

$('.sortable-handler').on('touchcancel', function (e) {
    e.preventDefault();
    console.log('touchcancel');
});

$('.sortable-handler').mouseleave(function (e) {
    e.preventDefault();
    console.log('mouseleave');
});

.. but all I get is:

Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080

Which event should I look for to get the updated list on every sort?

eozzy
  • 66,048
  • 104
  • 272
  • 428
  • This is a helpful article to understand the problem: https://developer.chrome.com/blog/scrolling-intervention/ Quoting: "impacted pages are fixed relatively easily by applying the touch-action CSS property whenever possible. If you wish to prevent all browser scrolling and zooming within an element apply touch-action: none to it." – Avatar Oct 31 '22 at 12:43
  • Also note: If your `touch-action: none;` does not work, it is likely that you have applied another `overflow` value to your wrapper. Then define `touch-action: none; overflow: hidden;` for your element. – Avatar Oct 31 '22 at 12:59

10 Answers10

113

See this blog post. If you call preventDefault on every touchstart then you should also have a CSS rule to disable touch scrolling like

.sortable-handler {
  touch-action: none;
}
frontendzzzguy
  • 3,242
  • 21
  • 31
Rick Byers
  • 3,136
  • 2
  • 16
  • 13
  • 7
    @Rick Byers, how can I add `preventDefault()` for `wheel mousewheel DOMMouseScroll` – Syed Jul 28 '17 at 13:31
  • @Rick Beyers. can you provide an example? I'm having the same problem with jquery mobile `swipe` event – Jonca33 Mar 03 '18 at 17:52
  • 1
    From the dev doc - If you have a horizontal carousel consider applying `touch-action: pan-y pinch-zoom` to it so that the user can still scroll vertically and zoom as normal. – Ishank Nov 15 '20 at 19:17
57

For me

document.addEventListener("mousewheel", this.mousewheel.bind(this), { passive: false });

did the trick (the { passive: false } part).

ranbuch
  • 1,584
  • 16
  • 14
28

In plain JS add { passive: false } as third argument

document.addEventListener('wheel', function(e) {
    e.preventDefault();
    doStuff(e);
}, { passive: false });
Halfacht
  • 924
  • 1
  • 12
  • 22
  • 3
    If you also need to use capturing instead of bubbling (meaning that the third argument would otherwise be `true`), the third argument should be `{capture: true, passive:false}`. See https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener for a complete list of options for the third argument. – Donald Duck Jun 20 '20 at 19:04
  • 2
    how can i do that for react's on listeners – AhmetEnesKCC Apr 25 '21 at 15:06
  • but that will block the scroll event too, page will get freeze on focus of this particular item – Pardeep Jain Dec 19 '22 at 13:26
10

To handle sortable list in Framework7 when user release currently sorting element in new position, you can use this code:

  $$('li').on('sortable:sort',function(event){
    alert("From " + event.detail.startIndex + " to " + event.detail.newIndex);
  });

Fiddle : https://jsfiddle.net/0zf5w4y7/

  • Ah man, how did you know about the event? Its not mentioned in their documentation. – eozzy Feb 08 '17 at 12:15
  • 2
    They have. They mentioned it at the bottom of page. See the documentation https://framework7.io/docs/sortable-list.html#sortable-events – Agus Sapurta Sijabat Feb 09 '17 at 04:53
  • Seems the same behavior can be triggered with the [App Instance Event](https://framework7.io/docs/sortable-list.html#app-instance-events) `sortableSort` – David Aug 26 '20 at 04:38
7

I am getting this issue when using owl carousal and scrolling the images.

So get solved just adding below CSS in your page.

.owl-carousel {
-ms-touch-action: pan-y;
touch-action: pan-y;
}

or

.owl-carousel {
-ms-touch-action: none;
touch-action: none;
}
Saurabh Solanki
  • 2,146
  • 18
  • 31
3

just do a check before call preventDefault

event.cancelable && event.preventDefault()

that's it!

More:

touchstart & touchmove default passive true due to perfomance, at most cases, you don't need to change that default optimize.

A.Chan
  • 620
  • 6
  • 7
1

To still be able to scroll this worked for me

if (e.changedTouches.length > 1) e.preventDefault();
Lance
  • 701
  • 6
  • 25
1

Adding to Rick Buyers' answer

See this blog post. If you call preventDefault on every touchstart then you should also have a CSS rule to disable touch scrolling like

.sortable-handler {
  touch-action: none;
}

here is how to do it in Javascript:

handlerList = document.getElementsByClassName("sortable-handler");
for (var i=0, len=handlerList.length|0; i<len; i=i+1|0) {
    handlerList[i].style.style.touchAction = "none";
}
Petr L.
  • 414
  • 5
  • 13
1

here is my solution for react. this is for silly react number textfield scrolling problem which causes number change while moving with wheel. when you try to preventDefault onWheel property you get "unable to prevent default inside passive event listener" error. Here we add event listener in creation.

export default function CustomTextField({ ...other }) {
  const ref = useRef(null);

  useEffect(() => {
    const element = ref.current;

    let isNumber = element.querySelector('input').type === 'number'
    if (isNumber) {
      element.addEventListener("wheel", handleWheel);
    }
  }, []);

  const handleWheel = (event) => {
    event.stopPropagation();
  };

  return (
        <TextField
          {...field}
          ref={ref}
          fullWidth
          value={typeof field.value === 'number' && field.value === 0 ? '' : field.value}
          error={!!error}
          helperText={error?.message}
          {...other}
        />

  );
}
Burk
  • 2,969
  • 1
  • 23
  • 24
0

I worked out a different solution for my code. I needed to disable the passive property for the touchend event. I was using jquery 3.5. You can try the below code:

jQuery.event.special.touchstart = {
        setup: function (_, ns, handle) {
            this.addEventListener('touchend', handle, { passive: !ns.includes('noPreventDefault') });
        }
    };
kumarras
  • 116
  • 5