14

So, I've run across an interesting problem while working on a Web application for the Microsoft Surface.

I want to add event listeners for when a user interacts with a DOM element. Now I can do:

if ('ontouchstart' in document.documentElement) {
  //Attach code for touch event listeners
  document.addEventListener("touchstart" myFunc, false);
} else {
  //Attach code for mouse event listeners
  document.addEventListener("mousedown" myFunc, false);
}

If the device didn't have a mouse input, this problem would be simple and the above code would work just fine. But the Surface (and many new Windows 8 computers) have BOTH a touch and mouse input. So the above code would only work when the user touched the device. The mouse event listeners would never be attached.

So then I thought, well, I could do this:

if ('ontouchstart' in document.documentElement) {
  //Attach code for touch event listeners
  document.addEventListener("touchstart" myFunc, false);
}
//Always attach code for mouse event listeners
document.addEventListener("mousedown" myFunc, false);

Devices that don't support touch wouldn't have the events attached, but a device that uses touch will register its handlers. The problem with this though is that myFunc() will be called twice on a touch device:

  1. myFunc() will fire when "touchstart" is raised
  2. Because touch browsers typically go through the cycle touchstart -> touchmove -> touchend -> mousedown -> mousemove -> mouseup -> click, myFunc() will be called again in "mousedown"

I've considered adding code tomyFunc() such that it calls e.preventDefault() but this seems to also block touchend as well as mousedown / mousemove / mouseup on some browsers (link).

I hate doing useragent sniffers, but it seems as if touch browsers have variations in how touch events are implemented.

I must be missing something because it seems that surely these JavaScript implementations were decided with possibility of a browser supporting both a mouse and touch!

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
userx
  • 3,769
  • 1
  • 23
  • 33

3 Answers3

2

For windows 8 you can use the "MSPointerDown " event.

 if (window.navigator.msPointerEnabled) {
     document.addEventListener("MSPointerDown" myFunc, false);
 }

Also add the following to your style:

  html { 
    -ms-touch-action: none; /* Direct all pointer events to JavaScript code. */
  }

See http://msdn.microsoft.com/en-us/library/ie/hh673557(v=vs.85).aspx for more info.

Cheshire
  • 86
  • 1
  • 6
-1

Inside myFunc, check the event type. If it's touchstart, then do e.stopPropagation().

function myFunc(e) {
    if (e.type === 'touchstart') {
        e.stopPropagation();
    }
    //the rest of your code here
}
noypiscripter
  • 1,451
  • 1
  • 13
  • 13
  • This unfortunately doesn't work either because it could be a "mousedown" event on a Windows 8 laptop which has both a mouse and a touch screen. – userx Jul 23 '13 at 00:31
  • This breaks touch enabled devices from having click events. – OG Sean Oct 07 '21 at 18:16
-3

EDITED: If you use jQuery, you will be able to do like this:

var clickEventType=((document.ontouchstart!==null)?'mousedown':'touchstart');

$("a").bind(clickEventType, function() {
    //Do something
});

This will fire only one of the bind's event.

Found here: How to bind 'touchstart' and 'click' events but not respond to both?

Community
  • 1
  • 1
curly_brackets
  • 5,491
  • 15
  • 58
  • 102
  • 1
    This doesn't solve the problem. It simply attaches handlers for both events and as such I don't believe it prevents the possibility of BOTH events firing (and hence the attached function firing twice). – userx Jan 31 '13 at 21:22