17

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.

user850234
  • 3,373
  • 15
  • 49
  • 83

3 Answers3

42

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");
    }
};
Andreas Louv
  • 46,145
  • 13
  • 104
  • 123
  • 1
    Be careful when mapping touchstart commands to replace mouseclick commands. You lose one very valuable function of the click event. A click followed by a touchmove cancels the click. A touchstart followed by a touchmove will fire the touch/click regardless of the touchmove event. So if you accidentally click something, you can't drag your finger off the element to cancel the click. – Alex May 30 '12 at 18:57
  • @Alex You are right but you can again check if the target is the same on `touchstart` and `touchend`. And you can get the pageX and pageY under `event.originalEvent.targetTouches[0].pageX` and `pageY` and then check if the finger is moved. – Andreas Louv May 30 '12 at 20:49
  • @AndreasAL No, I know. But you didn't mention that in your solution ;-) – Alex May 31 '12 at 13:50
  • 6
    Returning false from the touch event handler prevents the mouse event from firing. – Glenn Sandoval Sep 06 '12 at 22:59
  • It would be better to test for event existence either as in [H Dog's answer](http://stackoverflow.com/a/13126368/423306) or with Modernizr. – rachel Jan 25 '14 at 21:09
  • @rachel the reason i just make the check using the user agent is that i didnt want to "pollute" the answer with more code than necessary – Andreas Louv Jan 26 '14 at 07:52
  • 1
    be careful with code like this. The windows surface supports touch event and also supports a mouse. If a user is using the mouse the touch events will never fire. – Chris Mar 17 '14 at 17:27
  • Glenn Sandoval's answer is the RIGHT way. Any answer involving parsing the navigator string is highly dubious. – podperson Oct 18 '14 at 17:46
  • @GlennSandoval But it will also prevent the event from bubbling the DOM. – Andreas Louv Aug 11 '15 at 09:17
23

Be careful with using a UA sniffer for iPad/iPod. You're ditching all Android devices with a solution like that! A better solution is to detect the touch support, it will work on all Mobile/Tablet devices:

var isTouchSupported = "ontouchend" in document;
FirstVertex
  • 3,657
  • 34
  • 33
  • 2
    Problem with this is that computers that support mouse + keyboard but also have a touch screen, will be supporting the event, but it will only be fired when the screen is clicked. – Andreas Louv Aug 11 '15 at 09:18
0

Extending H Dog answer. Here is the code that worked for me.

 if (isTouchSupported) {
    $('#playanimationbtn').off("mouseup");
    $('#stopanimationbtn').off("mouseup");
    $('#playanimationbtn').off("mousedown");
    $('#stopanimationbtn').off("mousedown");
    $('#playanimationbtn').off("click");
    $('#stopanimationbtn').off("click");
    document.getElementById("playanimationbtn").addEventListener("touchend", PlayAnimation);
    document.getElementById("stopanimationbtn").addEventListener("touchend", StopAnimation);
} else {
    $('#playanimationbtn').off("touchstart");
    $('#playanimationbtn').off("touchend");
    $('#playanimationbtn').off("touchmove");
    $('#playanimationbtn').off("touchend");
    $('#playanimationbtn').off("touchleave");
    $('#stopanimationbtn').off("touchstart");
    $('#stopanimationbtn').off("touchend");
    $('#stopanimationbtn').off("touchmove");
    $('#stopanimationbtn').off("touchend");
    $('#stopanimationbtn').off("touchleave");
    document.getElementById("playanimationbtn").addEventListener("click", PlayAnimation);
    document.getElementById("stopanimationbtn").addEventListener("click", StopAnimation);
}
saadat ali
  • 925
  • 9
  • 17