Soulwax
Soulwax

Reputation: 301

Phonegap 2.4.0 with Android 4.2 - strange double click behaviour

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.2 on a Nexus 4 device, like a double click (althoug I tapped it only once!).

<a href="#" onclick="$(this).append('test'); return false;" style="some styles...">some text</a>

libs in use:

After I clicked (or tapped) the link on my Nexus 4 (Android 4.2.2) the string 'test' is appended twice inside the app.

This does NOT happen when I test it as mobile web app directly in the android browser.

It also works on my Samsung S3 (Android 4.1.2) inside the app. No problem on iPhones, too.

Anyone else recognized this strange behavior? (and maybe was able to fix it? ;-) )

Upvotes: 11

Views: 6230

Answers (5)

Martin Kool
Martin Kool

Reputation: 4245

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...      
}

Upvotes: 0

Robson Braga
Robson Braga

Reputation: 342

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:

  • jQuery 1.9.1;
  • jQM 1.3.2;
  • Phonegap 3.5.0-0.21.14.

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);
    }
}

Upvotes: 0

Bryan Corey
Bryan Corey

Reputation: 760

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');
});

Upvotes: 2

Kaan Soral
Kaan Soral

Reputation: 1645

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

Upvotes: 0

Soulwax
Soulwax

Reputation: 301

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);

Upvotes: 15

Related Questions