I'm trying to create a horizontal scrolling container. In a precise case i need to revert e.preventDefault(); from a click.
I tried a lot of options, changing 'window.location.href' in the else statement seems to be a great option.
But i can't figure how to grab the href from the link clicked.
Any idea can help to achieve my goal. :)
slider.addEventListener('mouseup', () => {
isDown = false;
// Disable click event (for ever unfortunately)
if(moved === true) {
this.addEventListener('click', (e) => {
e.preventDefault();
});
} else {
// trying to reset click function
}
You can conditionally prevent a click event from firing on your slider by registering a click event listener that shares the moved variable with your mousedown and mousemove event listeners.
The { passive: true } option indicates that the listener does not call event.preventDefault(), and saves a lot CPU time particularly for the mousemove event which can fire several times per second.
The true parameter indicates that the event listener should be called before the event starts to bubble up from the target element. This allows it to prevent propagation even to listeners that were already added on the same element, as long as they didn't also set useCapture to true.
const slider = document.querySelector('input[type="range"]');
// prevent this if mousemove occurred between mousedown and mouseup
slider.addEventListener('click', () => {
console.log('click event fired on slider');
});
// fires just before click event
slider.addEventListener('mouseup', () => {
console.log('mouseup event fired on slider');
});
let moved = false;
// reset for each potential click
slider.addEventListener('mousedown', () => {
moved = false;
});
// indicate cancellation should occur for click
slider.addEventListener('mousemove', () => {
moved = true;
}, { passive: true });
// prevents click event if mousemove occurred between mousedown and mouseup
slider.addEventListener('click', event => {
if (moved) {
event.preventDefault();
event.stopImmediatePropagation();
}
}, true);
<input type="range" />
You should remove the event listener containing the event.preventDefault();.
In order to do that you have to save your function reference into a variable like so:
const preventClickHandler = (e) => e.preventDefault;
slider.addEventListener('mouseup', () => {
isDown = false;
// Disable click event (for ever unfortunately)
if(moved === true) {
this.addEventListener('click', preventClickHandler);
} else {
this.removeEventListener('click', preventClickHandler);
}
})
Related
I want avoid that double click also fire a single click event.
A simple solution i found is to delay the click with a timer and destroy the timer if a double click is fired.
var pendingClick;
function myclick(){
clearTimeout(pendingClick);
pendingClick = setTimeout(function(){
console.log('click');
}, 500);
}
function mydblclick(){
clearTimeout(pendingClick);
console.log('double click');
}
<div onclick="myclick()" ondblclick="mydblclick()">Double Click Me!</div>
But this solution is based on timing, if the double click is too slow (>500ms) it also fire a single click.
There is a stable solution for handle both click and double click?
Double-clicking in itself is "based on timing", even in the standard implementation of dblclick / ondblclick. There will always be the issue of a single-click being fired if the double-click is "too slow". What is "too slow"? 300ms? 500ms? 1000ms? Your double-clicks may be only 50ms apart, while my mom's double-clicks are 1-2 seconds apart...
You can get the event and cancel it with the addEventListener like this:
document.addEventListener('dblclick', (event) => {
event.preventDefault();
event.stopPropagation();
}, true); // With this true, you are cancelling the dblclick event
let pendingClick;
function myclick(){
clearTimeout(pendingClick);
pendingClick = setTimeout(function (){
console.log('click');
}, 500);
}
function mydblclick(){
clearTimeout(pendingClick);
console.log('double click');
}
<div onclick="myclick()" ondblclick="mydblclick()">Double Click Me!</div>
Only work with the 'onclick' function to check if it was one or two clicks and use a variable to count the number of clicks in a given time interval.
Example:
var pendingClick;
var clicked = 0;
var time_dbclick = 500 // 500ms
function myclick(){
clicked++;
if(clicked >= 2){
mydblclick()
clearTimeout(pendingClick)
clicked = 0;
return;
}
clearTimeout(pendingClick)
pendingClick = setTimeout(() => {
console.log('One click!')
clicked = 0;
}, time_dbclick);
}
function mydblclick(){
console.log('double click');
}
<div onclick="myclick()">Double Click Me!</div>
Custom Events instead of inline event handlers
If one prefers to use .addEventListener and .removeEventListener instead of HTML inline-eventhandlers, I would suggest another approach based on Custom Events. That means one would not make use of the standard implementation of "click" and "dblclick", but create own event handling for both:
let lastLeftClick = document.dispatchEvent(new Event("click"));
let doubleclickLength = 300;
function leftClickHandler (e) {
if (e.button != 0) return; // only left clicks shall be handled;
let delaySinceLastClick = e.timeStamp - lastLeftClick.timeStamp;
let eIsDoubleClick = delaySinceLastClick < doubleclickLength;
if (eIsDoubleClick) {
let doubleclickEvt = new CustomEvent("doubleclick", e);
lastLeftClick = lastLeftClick = doubleclickEvt;
document.dispatchEvent(doubleclickEvt);
} else {
let singleClickEvt = new CustomEvent("singleclick", e);
lastLeftClick = singleClickEvt;
document.dispatchEvent(lastLeftClick);
}
}
// adding above click event implementation:
document.addEventListener("click", leftClickHandler);
using the new custom events:
document.addEventListener("singleclick", e=>console.log("single click"));
document.addEventListener("doubleclick", e=>console.log("double click"));
I have an event "pointerdown" but I want it to cancel the event call when a certain condition is met in one of the callbacks. So, all the next callbacks should not be called.
I have tried evt.preventDefault(); but that does not work, I have also tried evt.stopPropagation(); but that does not work.
const pointer = getMousePos(evt);
if (inBounds(pointer)) {
evt.preventDefault();
evt.stopPropagation();
}
The inBounds function returns true as expected, but the next callbacks of the event are still called. This event is added first, before the other events I wish to cancel but they are not.
If your listeners are attached on the same element, you will need to use stopImmediatePropagation() instead of stopPropagation()
The stopImmediatePropagation() method of the Event interface prevents other listeners of the same event from being called.
If several listeners are attached to the same element for the same event type, they are called in the order in which they were added. If stopImmediatePropagation() is invoked during one such call, no remaining listeners will be called.
https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation
You can also find a little description of the difference between both methods here:
stopPropagation vs. stopImmediatePropagation
Here a little demonstration of how you can use it. In this case, the second listener will never be called when the counter is a even number.
let counter = 0
const button = document.getElementById('TheButton')
button.addEventListener('click', e => {
counter++
console.log(`first listener: ${counter}`)
if (counter % 2 === 0) e.stopImmediatePropagation()
})
button.addEventListener('click', e => {
console.log(`second listener: ${counter}`)
})
<button id="TheButton">
OK
</button>
Use a global variable that you toggle to indicate whether the other event code should run.
let doBFunction = true;
element.addEventListener("pointerdown", function(evt) {
const pointer = getMousePos(evt);
if (inBounds(pointer)) {
doBFunction = false;
} else {
doBFunction = true;
}
// rest of code
});
element.addEventListner("pointerdown", function(evt) {
if (!doBfunction) {
return;
}
// rest of code
});
Hello I have implemented a long press javascript event handler which is working perfectly fine. However, on mobile, users tap...hold... in order to scroll up or down. This scrolling interaction on mobile is unintentionally triggering my 'pointerdown' event. I've tried inserting a pointermove event in the chain of event handlers but that seems to trigger an arbitrary amount of times, depending on how long the user is moving their pointer while pointerdown, therefore I am unable to set a boolean that is reliable and doesn't flip back and forth.
let pressTimer;
this.myElements.on('pointerup', (e) => {
clearTimeout(pressTimer);
}).on('pointerdown', (e) => {
let myEl = $(e.currentTarget);
let checkbox= myEl.find('.checkbox');
pressTimer = window.setTimeout(() => {
checkbox.click();
}, 750)
});
You could add a global boolean variable which holds the current status of the pointer (maybe isPointerDown) and act accordingly. e.g. if it's true don't react to pointerdown and if there's a pointerup event reset this variable to false.
let pressTimer;
var isPointerDown = false;
this.myElements.on('pointerup', (e) => {
clearTimeout(pressTimer);
isPointerDown = false;
}).on('pointerdown', (e) => {
if (!isPointerDown) {
let myEl = $(e.currentTarget);
let checkbox = myEl.find('.checkbox');
pressTimer = window.setTimeout(() => {
isPointerDown = true;
checkbox.click();
}, 750)
}
});
I have a button that fires a "stopstart" function (animation). I also want to have a mouseless method to do this so I've bound the same function to the space bar. This works.
However if focus is on the button, and I press space - both events fire, can't work out how to stop this (the keypress event fires first - in chrome..)
Eventlistener code:
document.getElementById("stopstart").addEventListener("click",
function (event) {
stopstart();
}); //add event listener to "stopstart" button
document.addEventListener("keypress",
function (event) {
if (event.keyCode === 32) { //space key
stopstart();
}
}); //add spacekey event listener to document
I don't want to remove focus from the button, as I'd like to retain that functionality - the two events appear to be separately generated - so I haven't found how to detect that the click event was in fact generated by the space bar.
Is this solvable using without having to add temporary flags to catch it etc
The click location for key events is zero, zero so you can look for that.
document.getElementById("stopstart").addEventListener("click",
function (event) {
var x = event.x || event.clientX;
var y = event.y || event.clientY;
if (!x && !y) {
alert("key press");
return false;
}
stopstart();
});
http://jsfiddle.net/mScEC/
function (event) {
if (event.pointerType !== "mouse") return;
stopstart();
}); //add event listener to "stopstart" button
document.addEventListener("keypress",
function (event) {
if (event.keyCode === 32) { //space key
stopstart();
}
}); //add spacekey event listener to document```
You can simply use event.preventDefault() inside keypress event Listener to prevent the Button Click event from getting triggered on keypress
e.g
document.addEventListener('keydown', function (e) {
e.preventDefault();
if (e.key === 'Enter') {
try {
// if expression is not evaluated then catch block will be executed
screen.value = eval(screen.value);
}
catch (error) {
console.log(error.message);
screen.value = 'Invalid Operation';
}
}
})
I have an element(textArea). Now I would like a long press event and a double click event on the element. I am able to do this but I would also like to use event.preventDefault() in the mousedown event of long press event. This in turn prevents the dblClick event also.
The reason why I want to preventDefault is I am rendering an element on longPress and wanted to prevent the initial mouseDown as I am firing mousemove after longpress. I have searched and re-searched the net but am unable to find a good answer which solves the problem of long press and dblclick on the same element.
thanks!!
try this Demo
HTML
<input type="button" ondblclick="whateverFunc()" onmousedown="func(event)" onmouseup="revert()" value="hold for long"/>
JavaScript
var timer;
var istrue = false;
var delay = 3000; // how much long u have to hold click in MS
function func(e)
{
istrue = true;
timer = setTimeout(function(){ makeChange();},delay);
// Incase if you want to prevent Default functionality on mouse down
if (e.preventDefault)
{
e.preventDefault();
} else {
e.returnValue = false;
}
}
function makeChange()
{
if(timer)
clearTimeout(timer);
if(istrue)
{
/// rest of your code
alert('holding');
}
}
function revert()
{
istrue =false;
}
function whateverFunc()
{
alert('dblclick');
}