Elliot
Elliot

Reputation: 2289

Prevent click event after mousedown & mouseup event

Is it possible with jQuery to prevent a click event on the same element from being executed, after a mousedown & mouseup event has just been fired.

Any help/examples would be appreciated.

Upvotes: 10

Views: 13484

Answers (5)

Sollace
Sollace

Reputation: 746

No one seems to have answered this one yet, at least not in an elegant way, so I figure I'll share the solution I found by NewbeDev (source: https://newbedev.com/cancel-click-event-in-the-mouseup-event-handler )

The answer is to use the capture phase, so before the event gets triggered on your element, all of its parents receive it during what's called the "capture phase". Then after that the event is delivered to your element followed by its parents in what's called the "bubbling phase".

The solution here is to just cancel the event at the top during the capture phase so it never reaches your element for the bubbling phase.

My use case was for a slider, so the code I used worked out to something like this:

slider.addEventListener('mousedown', ev => {
    // we start sliding (details omitted)

    function captureClick(e) {
        // we cancel the event and stop it from going further.
        // preventDefault() on its own should be enough for most cases
        // Your handler can also check e.defaultPrevented to know if preventDefault() was called
        e.preventDefault();
        // e.stopPropagation();
    }

   window.addEventListener('click', captureClick, true);
   document.addEventListener('mouseup', e => {
       // cleanup - we wait an extra frame to remove our capture 
       //           in case the click event is delayed
       requestAnimationFrame(() => {
           window.removeEventListener('click', captureClick, true);
       });
   });
});

Upvotes: 3

haravares
haravares

Reputation: 542

There is a solution:

const COORDS = {
  xDown: null,
  xUp: null
}

const handleOnMouseDown = e => {
  e.preventDefault()
  COORDS.xUp = null
  COORDS.xDown = e.clientX
}

const handleMouseUp = e => {
  e.preventDefault()
  COORDS.xUp = e.clientX
}

const handleOnClick = e => {
  if (COORDS.xDown !== COORDS.xUp) {
    e.preventDefault()
    console.log('drag')
  } else {
    console.log('click')
  }
}

const el = document.getElementById('test')

el.addEventListener('mousedown', handleOnMouseDown)
el.addEventListener('mouseup', handleMouseUp)
el.addEventListener('click', handleOnClick)
#test {
  padding: 20px;
  display: block; 
  background: #ccc
}
<a href="#" id="test">Link</a>

Upvotes: 1

neuront
neuront

Reputation: 9612

There's an awkward approach that is to disable the button when mousedown, and enable it after a short period, like 100ms. If the mouseup happens in this period, click won't be fired.

$('#btn').on('click', function() {
  alert('clicked')
});
$('#btn').on('mousedown', function() {
  var btn = $(this);
  btn.attr('disabled', 'disabled');
  setTimeout(function() { btn.removeAttr('disabled'); }, 100);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<body>
<button id='btn'>Click me</button>
</body>

Upvotes: 2

Louis Ameline
Louis Ameline

Reputation: 2889

In Chrome and Internet Explorer, not Firefox though, detaching and reattaching the element at mousedown or mouseup will prevent the click event to be triggered. In Internet Explorer, this trick does not catch double-clicks though (in Chrome it does).

But I wouldn't rely on this strange behavior, who knows if it won't change at some point. Also, beware that detaching and reattaching can also have side-effects ont the children of the detached element (iframes reloading, file fields reset, ...).

Upvotes: 1

chucktator
chucktator

Reputation: 1856

Yes, it should be possible if you return false; in the mouseup handler, because the onclick is fired after a mousedown and a mouseup have occurred. This is possible in regular javascript, so it should work with jquery event handlers as well.

EDIT:

Returning a boolean value from an event handler should actually be enough for event consumption. However, as this is very flaky across browsers you should use the function for manually canceling event bubbling:

event.stopPropagation();

where event is the parameter your event handler receives.

Upvotes: -3

Related Questions