user850234 user850234 - 6 months ago 110
jQuery Question

Click event called twice on touchend in iPad

I am using jquery animate for the slide. I have an arrow at the end of the slide and given the click event on that arrow. The working of it is to move one item inside the silde on click and move the entire silde on mousedown. This is working fine in desktop but in iPad two items are coming inside the slide at a time on click. I am not understanding why the click event is called twice in iPad. The sample code for the click is :

$('#next_item').bind('mousedown touchstart MozTouchDown',function(e) {
$('.slide').animate({left:left},6000);
});

$('#next_item').bind('mouseup touchend MozTouchRelease',function(e) {
No.nextItem();
});


#next_item
is the id of the arrow at the end of the slide. I have tried to
unbind
touchstart
and
touchend
event but during slide scroll due to unbind the item does not come inside the slide after single item.
No.nextItem()
moves one item inside the slide.
left
in
$('.slide')
is to move the slide left. Please help me find the solution why this is happening and how to solve this issue for ipad.

Answer

iPad both understands touchstart/-end and mousestart/-end.

Is gets fired like this:

┌─────────────────────┬──────────────────────┬─────────────────────────┐
│Finger enters tablet │ Finger leaves tablet │ Small delay after leave │
├─────────────────────┼──────────────────────┼─────────────────────────┤
│touchstart           │ touchend             │ mousedown               │
│                     │                      │ mouseup                 │
└─────────────────────┴──────────────────────┴─────────────────────────┘

You have to detect if the user is on a tablet and then relay on the touch start things...:

/********************************************************************************
* 
* Dont sniff UA for device. Use feature checks instead: ('touchstart' in document) 
*   The problem with this is that computers, with touch screen, will only trigger 
*   the touch-event, when the screen is clicked. Not when the mouse is clicked.
* 
********************************************************************************/
var isIOS = ((/iphone|ipad/gi).test(navigator.appVersion));
var myDown = isIOS ? "touchstart" : "mousedown";
var myUp = isIOS ? "touchend" : "mouseup";

and then bind it like this:

$('#next_item').bind(myDown, function(e) { 

You can also make a event that takes care of it, see:

http://benalman.com/news/2010/03/jquery-special-events/

Basic normalized down event:

$.event.special.myDown = {
    setup: function() {
        var isIOS = ((/iphone|ipad/gi).test(navigator.appVersion));
        var myDown = isIOS ? "touchstart" : "mousedown";
        $(this).bind(myDown + ".myDownEvent", function(event) {
            event.type = "myDown";
            $.event.handle.call(this, event);
        });
    },
    teardown: function() {
        $(this).unbind(".myDownEvent");
    }
};

After jQuery 1.9.0 $.event.handle changed name to $.event.dispatch, to support both you can write use this fallback:

// http://stackoverflow.com/questions/15653917/jquery-1-9-1-event-handle-apply-alternative
// ($.event.dispatch||$.event.handle).call(this, event);
$.event.special.myDown = {
    setup: function() {
        var isIOS = ((/iphone|ipad/gi).test(navigator.appVersion));
        var myDown = isIOS ? "touchstart" : "mousedown";
        $(this).bind(myDown + ".myDownEvent", function(event) {
            event.type = "myDown";
            ($.event.dispatch||$.event.handle).call(this, event);
        });
    },
    teardown: function() {
        $(this).unbind(".myDownEvent");
    }
};