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

If you'd like to confirm this for yourself, modify the todo.js 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 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
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:

  $('#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: