I\'m using phonegap 2.4.0 to create an Android and iOS App.
Now I recognized that the onclick event in links is fired twice inside the Android App using Android 4.2.
My fix was a little bit different. I've used touchend
instead click
event listener, because click
doesn't fire each time it's needed. Let's say you click a button, the click event listener is fired, but if you click that button again it is not.
It happens to any kind of DOM element. My environment is:
Here is my code:
if (window.cordova) {
// hack to avoid double tap
var lastTapTime = new Date().getTime();
function tryToAvoidDoubleTap(e){
var tapTime = e["timeStamp"];
if (tapTime && (tapTime - lastTapTime) < 300) {
// prevent double tap to happen
e.stopImmediatePropagation();
e.preventDefault();
// jQM button handling
if ($('.ui-btn').length)
$('.ui-btn').removeClass('ui-btn-active');
return false;
}
lastTapTime = tapTime;
}
// Wait for PhoneGap to load
document.addEventListener("deviceready", onDeviceReady, false);
// PhoneGap is ready
function onDeviceReady() {
document.addEventListener("touchend", tryToAvoidDoubleTap, true);
}
}
I think the reason of these double/multiple clicks are malfunctioning hardware accelerations, I'm experiencing simultaneous clicks + propagation's, propagation's are easy to prevent, however since third argument of addEventListener isn't respected in my case, I can't prevent double click even with the previously answered code, here is what I ended up using
function cw(event) // click wall
{ try {
click_time_cw = (new Date()).getTime();
if (click_time_cw && (click_time_cw - last_click_time_cw) < 350) {
event.stopImmediatePropagation();
event.preventDefault();
add_log('prevented misclick [CW] '+(click_time_cw - last_click_time_cw));
return true;
}
last_click_time_cw = click_time_cw;
event.stopImmediatePropagation();
event.stopPropagation();
return false;
} catch(e){ add_alert(e,"stpr"); } }
you also have to initialize last_click_time_cw=(new Date()).getTime() somewhere
this is an example onclick:
<button class="btn" onclick="if(cw(event)) return true; onclick_logic()">something</button>
it might seem like a lot of work and an unpleasant/ugly fix, but click problems have been haunting me for months, it seems like this is what I should've done from the begining
I handled my similar situation very closely to Soulwax's solution, however I didn't want to hinder fast clicks by the user by keeping track of time intervals. Instead, I simply track the event type in the link's data object and if it's trying to handle a click immediately after a touchstart I ignore that call.
$('.link').on('touchstart click', function(e){
e.preventDefault();
//Prevent against handling a click immediately after touchstart.
if(e.type == "click" && $(this).data("lastTouch") == "touchstart"){
e.stopImmediatePropagation();
return false;
}
$(this).data("lastTouch", e.type);
$('.nav-bar').toggleClass('active');
});
I was facing the exact same issue, but my app/game needed the user to be able to double tap, on touchstart. So the scirra solution mentioned above wasn't usable as a required delay of 500 or 1000 ms kills the doubletap.
After some digging I noticed a difference between the first (user) tap and the second (bug) tap:
event.originalEvent.touches
isn't available in the second bug tap. So I wrote this bug detection helper which solved my case:
function isDoubleTapBug (e) {
// only handle touch events (in case your listener works on mouse events too)
if (!'ontouchstart' in document.documentElement))
return false;
if (!e.originalEvent.touches) {
e.preventDefault();
e.stopPropagation();
return true; // indicate to caller that it's a bug
}
return false;
}
Then in your listener, do this:
document.addEventListener('touchstart', function (e) {
if (isDoubleTapBug(e))
return false;
// now do your actual event handling stuff...
}
Using a temporary solution from scirra.com
last_click_time = new Date().getTime();
document.addEventListener('click', function (e) {
click_time = e['timeStamp'];
if (click_time && (click_time - last_click_time) < 1000) {
e.stopImmediatePropagation();
e.preventDefault();
return false;
}
last_click_time = click_time;
}, true);