Unable to preventDefault inside passive event listener
Asked Answered
C

11

106

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?

Catinacation answered 7/2, 2017 at 23:8 Comment(2)
This is a helpful article to understand the problem: 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."Geniagenial
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.Geniagenial
N
11

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/

Nubilous answered 8/2, 2017 at 10:1 Comment(3)
Ah man, how did you know about the event? Its not mentioned in their documentation.Catinacation
They have. They mentioned it at the bottom of page. See the documentation framework7.io/docs/sortable-list.html#sortable-eventsNubilous
Seems the same behavior can be triggered with the App Instance Event sortableSortSaracen
S
117

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;
}
Stuckey answered 17/2, 2017 at 2:32 Comment(4)
@Rick Byers, how can I add preventDefault() for wheel mousewheel DOMMouseScrollPich
@Rick Beyers. can you provide an example? I'm having the same problem with jquery mobile swipe eventBastinado
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.Mancino
Atleast for chrome, with passive listeners, no need to call preventDefault. My situation is that my event listener and related functionality is inside a package, which I cannot touch/override, touch-action:none do help on the browser, but I will still see the warnings in the console log: Unable to preventDefault inside passive event listenerPastiness
T
60

For me

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

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

Teredo answered 14/4, 2019 at 8:56 Comment(2)
it worked for me without bind mouseweel. I used it instead of e.preventDefault. window.addEventListener('wheel', { passive: false })Forepleasure
Adding the passive:false after the pseudo function fixed the issue for me.Impoverish
M
30

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

document.addEventListener('wheel', function(e) {
    e.preventDefault();
    doStuff(e);
}, { passive: false });
Martijn answered 29/12, 2019 at 16:0 Comment(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 developer.mozilla.org/en-US/docs/Web/API/EventTarget/… for a complete list of options for the third argument.Lessard
how can i do that for react's on listenersWahoo
but that will block the scroll event too, page will get freeze on focus of this particular itemReiss
N
11

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/

Nubilous answered 8/2, 2017 at 10:1 Comment(3)
Ah man, how did you know about the event? Its not mentioned in their documentation.Catinacation
They have. They mentioned it at the bottom of page. See the documentation framework7.io/docs/sortable-list.html#sortable-eventsNubilous
Seems the same behavior can be triggered with the App Instance Event sortableSortSaracen
U
8

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;
}
Underpinning answered 28/11, 2019 at 6:12 Comment(2)
Thanks for the answer, I was specifically looking for owl-carousal, and this worked like a charm :)Uzzial
Great Answer. Owl Carousel things lmaoPromulgate
F
7

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.

Forgo answered 2/11, 2021 at 3:8 Comment(1)
.cancelable worked for me.Libbey
H
2

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";
}
Hunley answered 16/10, 2021 at 19:8 Comment(0)
S
1

To still be able to scroll this worked for me

if (e.changedTouches.length > 1) e.preventDefault();
Sybarite answered 9/9, 2020 at 19:38 Comment(0)
E
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}
        />

  );
}
Enenstein answered 23/9, 2022 at 21:51 Comment(0)
S
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') });
        }
    };
Shahaptian answered 30/11, 2021 at 9:52 Comment(0)
R
0

In my case, for React with TypeScript, I had to add and remove the event with passive set to false and call stopPropagation. CSS modifications were not needed.

  export const TableHeader = () : JSX.Element => {
    const ref = useRef<HTMLTableCellElement | null>(null)

    useLayoutEffect((): (() => void) => {
      if (ref.current == null) return () => {}

      const stopPropagation = (e: WheelEvent): void => {
        e.stopPropagation()
      }

      ref.current.addEventListener('wheel', stopPropagation, {
        passive: false,
      })

      return (): void => {
        if (ref.current == null) return

        ref.current.removeEventListener('wheel', stopPropagation)
      }
    }, [])

    
    return <th ref={(r) => (ref.current = r)}>Header content</th>
}
Rollmop answered 9/11, 2023 at 10:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.