Touch events: handle swipe differently from click? - javascript

I've got a Backbone app, and I'm using Modernizr.
On touch devices, I can't swipe the page to scroll it down, because touch events are triggering Backbone listeners and a series of complex events, rather than the usual page scroll.
This is my code:
events: function () {
if (this.modernizr.touch) {
return {
'touchstart .hover': 'onTouchStart'
};
} else {
return {
'mousemove .hover': 'onMouseMove'
};
}
}
// onTouchStart and onMouseMove both fire a listener
What event should I be using to distinguish swipe from click, so that swipe allows the user to move the page as normal? (I can't easily test on a touch device, just so you know this isn't a lazy question.)

Is your onTouchStart function calling event.preventDefault()? If so, that’ll stop the event triggering the native swipe-to-scroll behaviour. Removing that call should allow users to scroll normally.
This HTML5 Rocks article goes into quite a bit of detail about how touch events propagate/cascade.
Side note: The pattern you’ve used here makes a few dangerous assumptions IMO:
By only binding mouse events if Modernizr.touch is false, users with hybrid devices (touch-capable laptops etc) won’t be able to use the mouse/trackpad; why not just bind both events?
Some browsers/devices can’t fire touchstart or mousemove (keyboard users, Windows smartphones, etc) so won’t be able to use this functionality; if you bind to click events too as a fallback, you’d have them covered
I recently wrote an article about what I consider the “golden pattern” to cover all eventualities, if you’re interested.
Of course if the functionality those handlers provide is non-critical these things might not be a problem.

Related

How can I prevent a browser from generating ContextMenu event for a long touch

Browsers support touch events and might generate mouse events. Also, for a long touch the browser generates a ContextMenu event. However, in my industrial environment, I want all touch events to be handled like a click event. Is there a global setting to prevent the browser to generate context menu events? Or can I at least set the time when the browser will generate such an event?
My only solution I came up with so far is the subscribe to click and context menu events and call the same handler. However I would rather avoid this for every button in my application...
Any ideas?
There are several answers at Disabling the context menu on long taps on Android
But I think the most voted answer over there is not a good one.
Try and see if this work for you,
window.ontouchstart = function(event) {
event.preventDefault();
event.stopPropagation();
return false;
};

Would onClick event work on touch on touch-screen devices?

I've used onclick events in my website. But when I open it in google chromes' developer mode's mobile view, nothing happens on touch on the elements which work on click with mouse. So my question is:
Do I have to also add ontouch events along with onclick events, or onClick event work on touch on all touch-screen devices?
P.S: You can see all of my codes here: https://github.com/SycoScientistRecords/sycoscientistrecords.github.io/
Or at the live website: http://sycoscientistrecords.github.io
And no I haven't tested the website on real phone.
onclick works fine on touchscreens; I've used it several times and have never had any problem.
You could consider using onmousedown instead of onclick. Or use jQuery to detect taps.
I found this detailed writeup at MDN very helpful. In particular:
the browser may fire both touch events and mouse events in response to the same user input [emphasis mine]
and
the element's touch event handlers should call preventDefault() and no additional mouse events will be dispatched
So, your touchstart or touchend listener can call evt.preventDefault() and your mousedown / mouseup listeners won't fire because they come later in the chain.
In Angular, I was able to detect whether I'd clicked a button using my mouse or my laptop's touchscreen, by changing (click)="doSomething()" to (mouseup)="doSomething(false)" (touchend)="doSomething(true); $event.preventDefault()". The method is called with true for touch events and false for mouse events.
onclick may not work on touch devices, I had this issue and the event ontouchstart sorts it.
if you use ontouchstart and onclick watch that you don't trigger the event twice.
this is another post related
onClick not working on mobile (touch)
New browsers have a pointerType which determines if the onClick is made by a mouse or via a touch. If you just want make adjustments in user behavior based on the input, using pointerType is the safest way.
if you are using jQuery:
$(selector).click(e => {
if (e.pointerType === "mouse") {} // mouse event
else {} // touch event
});
if you are using vanilla JS:
element.addEventListener('click', e => {
if (e.pointerType === "mouse") {} // mouse event
else {} // touch event
});
If you are using React, the event is wrapped around a synthetic event. To access the pointerType, you have to use the nativeEvent of the react event. Here is what you need to consider (especially if you are using Typescript). If the event is triggered by a mouse, the native event is an instance of MouseEvent which does not have pointerType, so, first you need to check the type of native event which will also take care of the typing problems in TS
<div
onClick={e => {
if (e.nativeEvent instanceof PointerEvent && e.nativeEvent.pointerType === 'touch') {} // Touch Event
else {} // Mouse Event
}}
></div>
Pro tip: If you want to test the touch event in development, use Chrome following this. Note that Safari has a responsive mode which simulates the framework of iPhones and iPads. However, Safari always registers a mouse event even when you are in responsive design mode and have selected an iPhone or iPad.

Responsive website: why would touchstart be needed instead of click?

I'm developping a complex Single-Page-Application using ReactJS.
This page was initially a desktop browser application with lots of "onclick" listeners everywhere, including internal code, but also external plugins/libs that we can't modify easily.
But now we made it responsive, and it is available in both a mobile website and a Cordova/Phonegap app.
Just making the CSS responsive produces a nice result, without introducing touchstart event at all.
When the user touch an element with a click listener, the listener is called and the click event bubbles correctly (except on iOS but it can be solved)
So, unless I'm trying to implement touch specific complex features like drag&drop with touch, or special "synthetic events" like press, pinch, tap, swipe, (often provided by mobile-specific libraries), why would I need to use touchstart in any way?
For example I often see people trying to mix both click and touchstart in applications according to the device capabilities.
But if click works, why would I need to care about touchstart?
What are the advantages of touchstart that are not handled by click already?
Note: this is NOT at all about the 300ms click delay which can be solved in other ways.
The only reason we use touchstart/touchmove are for drag events, such as scrolling/inner-scolling detection.
For example, we want to detect the end of a scroll for infinite scroll.
On desktop we can use:
$('.whatever').scroll({ blahhhh
but on mobile we use:
$('.whatever').on('touchmove', blahhhh
Also you should definitely checkout How to bind 'touchstart' and 'click' events but not respond to both?

A tag getting click instead of touchstart [duplicate]

I have a bootstrap .btn that I want to toggle with the mouse click. The problem is that the response is way too slow on tablets, since the click arrives 300 ms after the touchstart in mobile browsers.
I tried binding the logic in the touchstart event, effectively breaking the app for desktop browsers where there is no touchstart. I then thought of binding the same logic also to click but then I get a repeated event in mobile browsers. I've juggling around, trying to unbind from click the first time I receive a touchstart, and so on, and managed to come up with a design so complicated that there is always some quirk here or there that I cannot solve.
For instance, I can't get a text input to receive focus in the tablet: if I do focus on touchstart then the click event returns the focus to the button. I tried jQuery Mobile's vmousedown, but I couldn't manage to have multi-touch (tapping more than one button at the same time only changed one of them). I don't want to reinvent a lot of wheels, and I'm sure I must be missing something obvious, either on jQuery Mobile, or plain JavaScript.
In concrete, I want an event like vmousedown that works both on desktops and mobiles, only fires once on each, and allows multi-touch.
Utilize Modernizr for handling actions based on the device, etc. It provides great cross-browser/platform support without the need to sniff User Agents and the like. Instead, it uses feature detection.
You can just use the Modernizr functions with jQuery's $(document).ready(function()});
$(function(){
if (Modernizr.touch){
// bind to touchstart, touchmove, etc and watch `event.streamId`
} else {
// bind to normal click, mousemove, etc
}
});
This code has been taken straight from the Modernizr Documentation
Also, here's another resource for performing touch tests
Late to the party, but note that jQueryMobile also has similar touch detection:
if ( $.mobile.support.touch ) {...
And no, IMHO, you are not missing anything obvious :), cross-platform / cross-device / touch-friendly features are still harder than they should be. For example, today I'm looking at a win8 surface tablet: touch-screen and a mouse. There are cases where i'd like to know which device was used. event.originalEvent.type should differentiate between tap and click, right? wrong :(.

Unified and transparent pointer events in jQuery

I have a bootstrap .btn that I want to toggle with the mouse click. The problem is that the response is way too slow on tablets, since the click arrives 300 ms after the touchstart in mobile browsers.
I tried binding the logic in the touchstart event, effectively breaking the app for desktop browsers where there is no touchstart. I then thought of binding the same logic also to click but then I get a repeated event in mobile browsers. I've juggling around, trying to unbind from click the first time I receive a touchstart, and so on, and managed to come up with a design so complicated that there is always some quirk here or there that I cannot solve.
For instance, I can't get a text input to receive focus in the tablet: if I do focus on touchstart then the click event returns the focus to the button. I tried jQuery Mobile's vmousedown, but I couldn't manage to have multi-touch (tapping more than one button at the same time only changed one of them). I don't want to reinvent a lot of wheels, and I'm sure I must be missing something obvious, either on jQuery Mobile, or plain JavaScript.
In concrete, I want an event like vmousedown that works both on desktops and mobiles, only fires once on each, and allows multi-touch.
Utilize Modernizr for handling actions based on the device, etc. It provides great cross-browser/platform support without the need to sniff User Agents and the like. Instead, it uses feature detection.
You can just use the Modernizr functions with jQuery's $(document).ready(function()});
$(function(){
if (Modernizr.touch){
// bind to touchstart, touchmove, etc and watch `event.streamId`
} else {
// bind to normal click, mousemove, etc
}
});
This code has been taken straight from the Modernizr Documentation
Also, here's another resource for performing touch tests
Late to the party, but note that jQueryMobile also has similar touch detection:
if ( $.mobile.support.touch ) {...
And no, IMHO, you are not missing anything obvious :), cross-platform / cross-device / touch-friendly features are still harder than they should be. For example, today I'm looking at a win8 surface tablet: touch-screen and a mouse. There are cases where i'd like to know which device was used. event.originalEvent.type should differentiate between tap and click, right? wrong :(.

Categories

Resources