Home › Forums › JavaScript › Touch device ghost click triggers on different element
- This topic is empty.
-
AuthorPosts
-
March 19, 2017 at 12:37 am #252922ShikkedielParticipant
Looking at the answers on SO, I believe most of these script work because of using
preventDefault()
ontouchstart
. The only touch event for which it will have a cross browser reliably effect that will prevent it getting emulated into a click. Going withtouchstart
andclick
is the shortest route of course, although all native behaviour (scroll, swipe) will be disabled when starting the interaction on the element in question.It’s going a bit out of the scope of the original issue but the custom event I put together has a shortcoming as well that is in the same sphere. Which is that if you happen to touch an element with the event listener and start scrolling, after removing the finger the event might get triggered. I may have to add a solution for that (likely awkward and overly complicated with Android again) on the page that had the issues.
Some good info for future reference:
March 19, 2017 at 3:25 am #252927ShikkedielParticipantNever mind this one, I’ll check the code again first.
For now I can’t see straight anymore…March 19, 2017 at 5:56 am #252939ShikkedielParticipantFor now I can’t see straight anymore…
Still enough to not stop, I suppose. :-/
But this one’s rather nice…
$('div').on('touchstart click', {flag: false}, function(e) { if (e.type == 'click' && e.data.flag) return; e.data.flag = e.type == 'touchstart'; //do stuff on either event });
Even though it doesn’t reset, which would be convenient with devices that support both.Now I’m calling it a day…
$('div').on('touchstart touchcancel click', {flag: false}, function(e) { if (e.type == 'touchcancel' || e.type == 'click' && e.data.flag) { e.data.flag = false; return; } e.data.flag = e.type == 'touchstart'; //do stuff on either event });
March 19, 2017 at 10:51 pm #252944ShikkedielParticipantI’ve heard that this solution from Stackoverflow takes care of the ghost click:
$(document).on('touchstart click', '.myBtn', function(event){ if(event.handled === false) return event.stopPropagation(); event.preventDefault(); event.handled = true; // Do your magic here });
Looks like that was extracted from some jsbin code:
That doesn’t seem to work either, at least not with Firefox touch emulation. Even though using a flag at all doesn’t seem necessary when
preventDefault
is also in place…var kind; function TouchClick(sel, fnc) { $(sel).on('touchstart click', function(event) { event.stopPropagation(); event.preventDefault(); $('div span').append(event.handled + '<br>'); if (event.handled !== true) { kind = event.type; fnc(event); event.handled = true; } else { return false; } }); } TouchClick('div', function() { $('div span').append(kind + '<br>'); });
Here
event.handled
is just asundefined
on each occurence as with the smaller script.March 20, 2017 at 5:30 am #252949MottieMemberHehe thanks for continuing to work on this… did you try adding the css property?
March 20, 2017 at 9:47 am #252963ShikkedielParticipantThat’s a new concept for me so I’m still reading up on it. :-)
Googling a bit and landing on jQuery event data was a nice find too…I’m usually quite relentless when trying to get to the bottom of some code.
Often up to a point where I tire myself (and maybe even others) majorly. :-/March 20, 2017 at 10:05 am #252964ShikkedielParticipantFeel free to in return incorporate any of my fiddling-findings if you think it might enhance your own SO answer by the way, Mottie… the format there is of a wiki community after all. With 32 existing answers, I definitely won’t be adding one myself.
March 20, 2017 at 10:56 am #252966MottieMemberWell actually that question/answer on SO is about binding to touch & click events, not really about ghost clicks. I think you should find a question and add an answer there since you’re doing all this work – I’d up-vote you!… or at least write up a blog post somewhere and share a link here.
March 20, 2017 at 12:15 pm #252972ShikkedielParticipantI think the code at the top is what the other answer was intended to be but with all the details discussed in the comments, yours does look quite complete.
There was an underwhelming topic on SO where someone asked how to switch between touch and mouse. It already having an accepted answer, I suggested to listen to both by posting some rather crude and flawed code. Quite a while later someone found and upvoted this so I felt obliged to at least post a bug free version. That’s enough for me.
It’ll be a while before I turn the last stone on this and come up with the most ideal code…
March 22, 2017 at 6:46 am #253037ShikkedielParticipantOriginal “ghost click” issue – an old Android bug, sort of solved…
But here’s the final code I’m using to create a
page:tap
, eliminating the more commonly known ghost click that comes from touch events being emulated:function swiftClick(aim) { $(document).on('mousedown touchstart click', aim, {}, function(e) { var mean = $(e.currentTarget), info = e.data; if (e.type == 'mousedown' && (e.which != 1 || info.hit)) return; if (e.type == 'click') { delete info.hit; return false; } info.peg = Date.now(); mean.one('mouseup touchend', function(e) { if (e.type == 'touchend') info.hit = true; else if (info.hit) return; if (Date.now()-info.peg > 300) return; mean.trigger('page:tap'); }); }).on('page:tap', aim, function() { if ($(this).is('a')) window.location = this.href; }); }
Usage:
swiftClick('.something'); $('.something').on('page:tap', function() { // do whatever });
Using persistent event data’s a bit nicer than adding classes. Clicks on links will have their default behaviour blocked and get redirected by the script. Subsequent
touchstart-touchend
ormousedown-mouseup
will not trigger apage:tap
if it took longer than 300ms.It’s going a bit out of the scope of the original issue but the custom event I put together has a shortcoming as well that is in the same sphere. Which is that if you happen to touch an element with the event listener and start scrolling, after removing the finger the event might get triggered.
In fact, default
touchcancel
behaviour on many browsers will make thetouchend
not fire in that case which is quite convenient. But the 300ms time limit should also mostly solve it.March 22, 2017 at 7:02 am #253039ShikkedielParticipantOkay, small edits don’t seem to be allowed… let me post again.
Original “ghost click” issue – an old Android bug, sort of solved…
But here’s the final code I’m using to create a
page:tap
, eliminating the more commonly known ghost click that comes from touch events being emulated:function swiftClick(aim) { $(document).on('mousedown touchstart click', aim, {}, function(e) { var mean = $(e.currentTarget), info = e.data; if (e.type == 'mousedown' && (e.which != 1 || info.hit)) return; if (e.type == 'click') { delete info.hit; return false; } info.peg = Date.now(); mean.one('mouseup touchend', function(e) { if (e.type == 'touchend') info.hit = true; else if (info.hit) return; if (Date.now()-info.peg > 300) return; mean.trigger('page:tap'); }); }) .on('page:tap', aim, function() { if ($(this).is('a')) location = this.href; }); }
Usage:
swiftClick('.something'); $('.something').on('page:tap', function() { // do whatever });
Using persistent event data’s a bit nicer than adding classes. Clicks on links will have their default behaviour blocked and get redirected by the script. Subsequent
touchstart-touchend
ormousedown-mouseup
will not trigger apage:tap
if it took longer than 300ms.It’s going a bit out of the scope of the original issue but the custom event I put together has a shortcoming as well that is in the same sphere. Which is that if you happen to touch an element with the event listener and start scrolling, after removing the finger the event might get triggered.
In fact, default
touchcancel
behaviour on many browsers will make thetouchend
not fire in that case which is quite convenient. But the 300ms time limit should also mostly solve it. -
AuthorPosts
- The forum ‘JavaScript’ is closed to new topics and replies.