View Single Post
  #7 (permalink)  
Old April 7th, 2013, 11:37 PM
WilliamDoane WilliamDoane is offline
Registered User
Points: 30, Level: 1
Points: 30, Level: 1 Points: 30, Level: 1 Points: 30, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Apr 2013
Posts: 6
Thanks: 0
Thanked 1 Time in 1 Post
Default Solution

The problem is that the JQMobile TAP event responds to/simulates both a touchEnd event (for mobile devices) and a click event (for desktop browsers). This is an attempt to have the same JQM code work whether the user is visiting the site from a mobile or desktop device.

Unfortunately, in the simulator and on many mobile devices, this triggers TWO events at the same X, Y coordinate: first a touchEnd event on the add button is fired; the add button hides itself and shows the cancel button; and then the cancel button receives the click event. (This has been tested and confirmed.) In a desktop browser, only one event is triggered (click), so there's no problem.

More about this "ghost click" problem can be found at https://developers.google.com/mobile...s/fast_buttons.

If you'd like to confirm this for yourself, modify the todo.js code

Code:
  // Note the addition of the evt parameter
  $('#add').tap(function( evt ) {
    $('#main').append(evt.originalEvent.type + " in #add.tap<br>");  // debug
  ...

  // and again, slightly further down...
  $('#cancel').tap(function( evt ) {
      $('#main').append(evt.originalEvent.type + " in #cancel.tap<br>");  // debug
  ...
Then compare loading todo.html in a Safari, mobile Safari, iOS simulator, etc. (you should see the same misbehavior on mobile and simulator devices as before).

I spotted a potential solution at http://forum.jquery.com/topic/tap-fi...-with-live-tap posted by the_new_mr. Their approach is to remember the timestamp of the last event and, if the next event follows too closely in time, ignore it. The proposed inter-event threshold is 800 milliseconds.

At the top of todo.js, add
Code:
var lastTapTime;

function isJqmGhostClick() {
    var threshold = 800; // milliseconds
    var currTapTime = new Date().getTime();
    
    if(lastTapTime == null || currTapTime > (lastTapTime + threshold)) {
        lastTapTime = currTapTime;
        return false;
    }
    else {
        return true;
    }
}

Then, add one line to the beginning of the #add.tap and #cancel.tap event callback functions:

Code:
  $('#add').tap(function() {
    if (isJqmGhostClick()) return;
...

  $('#cancel').tap(function() {
    if (isJqmGhostClick()) return;
...

Last edited by WilliamDoane; April 8th, 2013 at 12:41 PM.. Reason: added code for users to be able to confirm the source of the problem themselves
Reply With Quote
The Following User Says Thank You to WilliamDoane For This Useful Post: