I have a touchscreen, if you dont get the button press timing exactly right on chrome, which is about 50% of the time for everyone, the click() does not register. If you press a button too long it just sort of focusses it (without firing a focus event). If you press a button too quickly, it ignores it as a mistake. So currently the touchscreen is very hard to use.
Althought I say button above, its actually a label for a radio input, but occurs on buttons too.
After diving into problem, I have figured out its not focus events, but the following events that are firing depending on how one presses the button:
Code to print the events:
['focus', 'contextmenu', 'touchstart', 'touchend', 'touchcancel', 'touchmove', 'click'].forEach( eventName => { document.addEventListener(eventName, event => console.log(eventName)) });
And these are the type of presses:
// Context menu (slightly longer press)
touchstart
contextmenu
touchend
// Touch move (not stead finger press)1
touchstart
touchmove x N
touchend
// Touch move and context menu (combination of above)
touchstart
contextmenu
touchmove
touchend
// Got it right, click occurred
touchstart
touchend
click
I tried:
document.addEventListener('touchstart', event => { event.preventDefault(); event.target.click();} )
But then if you get the click correct, it will fire a second click. I wish to convert all the above scenarious into just a single click.
You could pass a debounced (or throttled) version of your event listener to all the functions like so:
// copied from https://davidwalsh.name/javascript-debounce-function
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const myDebouncedFunction = debounce(myHandler, 100, true);
document.addEventListener('touchstart', myDebouncedFunction);
document.addEventListener('click', myDebouncedFunction);
... whatever other events you want to attach to
Alternatively if you use lodash you can use their built-in debounce function.
Thanks to Tom, I created a simplified debounce, it there has been no click within 100ms after the touchend event, then fire one off.
var touchedEl = null;
document.addEventListener('click', () => touchedEl = null);
document.addEventListener('touchend', event => {touchedEl=event.target; setTimeout(() => { touchedEl && touchedEl.click() }, 100)})