Handling clicks for mobile platforms [UPDATED]

1 Comment

I’ve been doing a lot of work in Phonegap lately and I really like it.  However, one of the things I don’t like is that click events are really, really slow.  There’s a reason for this.  How does the browser know if it’s a click or the beginning of a move?  The answer to this is to bind your click events to the “touchend” event.

So, in JQuery you would previously do something like this.

1
target.bind('click', callback);

But that introduces the lag.  So I wrote a little function where instead of calling bind() I would call this function instead.  It would determine if it’s a desktop or mobile device and then either register the click event or the touchend event.

However, there is a problem with this.  The touchend call might come at the end of a move, in which case you don’t want to fire the click event’s callback.  So I wrote a little bit of code that checks for a move event and then unbinds the touchend event, storing the callback in the new function called at touchend.  If there is no move event the callback is called at touchend.  If the move event is not thrown the callback is re-bound at touchend so the next time a “click’ event is triggered the event will be there to handle it.

1
2
3
4
5
6
7
8
9
target.bind('touchmove', function() {
  var cb = callback;
  $(this).unbind('touchend', cb);
  $(this).bind('touchend', function() {
    var cbb = cb;
    $(this).bind('touchend', cbb);
    });
  });
target.bind('touchend', callback);

[EDIT]

It turns out that this is wrong.  One of the things that I neglected to see offhand was that this code was fine… IF only one touchmove event was fired.  However, if many were fired the callback would be added for each time touchmove was called.  If your finger was moving a lot, then a lot of calls to the callback would be executed on touch end.

Here is code that actually works properly.

1
2
3
4
5
6
7
8
9
10
11
12
target.bind('touchmove', function() {
  $(this).data('moved', true);
});
target.bind('touchend', function() {
  if ($(this).data('moved')) {
    $(this).data('moved', false);
    return;
  }
  $(this).data('moved', false);
  $(this).trigger('touchendnomove');
});
target.bind('touchendnomove', callback);

What this does differently is simply set a flag if a touchmove event is fired.  Then on touchend it checks to see if the flag has been set.  If not a CUSTOM event is fired.  This is important because we want $(this) to refer to the target when an event is fired.  This way we don’t have to do any magic to get the proper “this” association done and we don’t have the problem of those pesky touchmove events.

One thought on “Handling clicks for mobile platforms [UPDATED]

Leave a Reply

Your email address will not be published. Required fields are marked *