jQuery and jQuery Mobile : tap vs touchstart, touchend, touchmove and click? - javascript

Does the jQuery Mobile Tap corresponds to adding an event listener to an element like this:
myElement.addEventListener("touchstart", touchStartHandler, false);
If so, what about the remaining normal events such as touchmove, touchend and so on? I mean what is their equivalent in jQuery Mobile?
Thank you for guiding me.

Internally tap makes use of vclick.
If you don't find an event in this list, they aren't exposed with the same name: https://api.jquerymobile.com/category/events/
This means, for example: if you need to handle touchstart, touchend and touchmove, as normally is, you will probably end up to use the set of virtualized mouse event handler: vmousedown, vmousemove, vmouseup and vclick but you may need to handle the status of the pointer (mouse or finger) by yourself. Do not forget to handle vmousecancel.
Moreover, you should note that there is a delay to wait for some events.
Following is a short extract for you, from the jQuery Mobile documentation with some critical concepts for touch devices (mobile or modern hybrid laptops) to pay attention to:
Webkit based browsers synthesize mousedown, mouseup, and click events
roughly 300ms after the touchend event is dispatched.
The jQuery Mobile taphold triggers after 750ms.
After 1500ms, then it is not a touch event. Scroll, TouchMove and
TouchEnd events use this. The block list is cleared.
We recommend using click instead of vclick anytime the action being
triggered has the possibility of changing the content underneath the
point that was touched on screen. This includes page transitions and
other behaviors such as collapse/expand that could result in the
screen shifting or content being completely replaced.
Have a nice day

I dont know if is exactly the same way they do the handle, but both of they wait for an action and then execute funciton.
in jquery mobile you can do
$("p").on("taphold",function(){
$(this).hide();
});
and
$(function(){
$( "div.box" ).bind( "tap", tapHandler );
function tapHandler( event ){
$( event.target ).addClass( "tap" );
}
});
list of events https://api.jquerymobile.com/category/events/

Related

Prevent Swipe events when interacting with elements on a page

I am building an iPad application which is essentially a series of slides.
When I've finished reading a slide I am able to swipe to the next slide *(using Zepto's swipe) which changes the window.location to the next slide. (the swipe event is bound to the window.body as it needs to work on the whole page)...
Here is the problem: some slides have interactive elements such as buttons, draggable items etc. The problem is that the swipe event is triggered when using some of these interactive elements.
Does anyone know of a way to prevent swipe from triggering in these instances? Perhaps settings a sensitivity etc?
I'm stumped...
Best wishes and many thanks!!
The way Zepto manages touch events is it binds listeners to the touchstart, touchend, and touchmove events on document.body. It then performs calculations on what event to send and triggers an event on the element that received the touchstart event. This event then bubbles up through the DOM tree evoking the listeners of each element.
This gives us two ways of preventing swipe events:
First, you could do something like:
$('#my-child-element').bind('touchstart touchend touchup', function(event) {
event.stopPropagation();
});
When your child element receives one a touch event, it will prevent it from propagating to parent elements, most importantly the body tag. This prevents the Zepto touch processor from doing anything, blocking swipe, tap, singleTap, longTap, and doubleTap events from occurring while operating in that element.
Because swipe events also bubble, you could also just prevent those specific events from bubbling to your element that listens to page change swipes:
$('#my-child-element').bind('swipeLeft swipeRight', function(event) {
event.stopPropagation();
});
This will allow you to still receive the Zepto generated events inside your child element but not outside. Zepto tap events will also still work for all elements within your child.
Fiddle here: http://jsfiddle.net/bnickel/dUuUd/
Hope "excludedElements" method will help you, like below.
$(".block").swipe({
swipe: function (event, direction, distance, duration, fingerCount, fingerData) {
},
excludedElements: ".link, a",
threshold: 0
});

Can mouseenter and click event exist together?

I am wondering if mouseenter and click event can exist together and they can both exist to TRUE when checked with:
if ((evt.type === 'mouseenter') && (evt.type === 'click'))
It is because when I mouse over the link, the mouseenter triggers (set to TRUE) and even when I clicked on it, the hover is still shown. Probably they could exist together but I'm no expert on this.
If someone can give insights, I would appreciate it a lot.
Also how can I trigger the click event during the mouseenter event?
The mouseenter event fires when the mouse enters the control. The click event fires when the mouse is clicked. They are two separate events which call two separate event handlers. If you click just as the mouse enters the element they will be called within a short timespan of one another but they are still two distinct events.
It is also important that you differentiate between the mouseenter and the mouseover events. mouseenter fires when the mouse physically enters an element, whereas mouseover fires continually while the mouse remains over an element.
While you cannot trigger the click event per se, you can call the same function that is called by the click event handler. For example if you have this:
var myfunc = function (e) { ... }
document.getElementById("id").onclick = myfunc;
Then you could simply call myfunc directly and you would get the same result as if the mouse was clicked.
They can 100% exist together, and this is a great question with no good answer... When you're on a mobile device, a mouseenter event will be thrown on tap... If you are also detecting onclick as well as mouseenter, then there will be a discrepancy between mobile devices and desktop machines.
It's kind of hard to solve such a small issue at the moment.
const x = document.getElementById('some_node')
x.onclick=(e)=>{
e.stopPropagation()
// this logic will be triggered on click for both desktop and mobile
}
x.onmouseenter=(e)=>{
e.stopPropagation()
// this logic will be triggered on click for mobile only (but will
//have already been triggered on desktop when cursor entered node)
}
The only workaround I came up for this, and I think it's pretty clever, is using a eventlistener for taps/touches. The order/priority that these events are fired goes: touch > mouseenter > click.
Since the touch event is fired first, you can add a touch event listener (which will only register on a mobile device), and change a variable that prevents the mouseenter event from being triggered (which is the logic that would generally be conflicting with the onclick logic)... like this:
let isMobile = false
x.addEventListener('touchstart',(e)=>{
isMobile = true
}, false);
Then your mouseenter would need to look like this:
x.onmouseenter=(e)=>{
e.stopPropagation()
if(!isMobile){
// this logic will no longer cause a conflict between desktop and mobile
}
}
they can exist on the same object, think a button with a hover state and then a click action. The click event, though will only read the click event since the enter event actually occurred earlier.
You can create a var like mouseIsOverand set it to true when the enter event fires. I can be safely assumed, though that if a click happens the mouse is over the same target.
The two events may happen at the same time, but they will still be processed on after the other. So the if you posted will never evaluate to true.
If you look at your code again you can see that it doesn't make sense. How can something be X and Y at the same time? It can't.
for the first question i think u got an answer....
however, for Also how can I trigger the click event during the mouseenter event?
u can use trigger() function..
http://jsfiddle.net/PDhBW/2/
if u want to read more about trigger
here is the link
http://api.jquery.com/trigger/
With Jquery event delegation, You can use binding multiple events at once
$('#IdElement').on('mouseenter click', function () {
//Your Code
});
http://jqfundamentals.com/chapter/events

When to use touchmove vs mousemove?

I build a web mobile game, it runs on browsers (PC/Mobile).
Do I need to use the touchmove or not?
How can I run the touchmove event like the mousemove event?
For parity between desktop and touch you have the following equivalences:
mousedown === touchstart
mousemove === touchmove
mouseup === touchend
Thus if you handle mousedown, mousemove and mouseup then you don't need to handle the corresponding equivalent events under touch. The same handlers should be executing.
Except on the ipad -- where mouse hover, mouse down, mouse up and click are all triggered... except if you change anything in mouse hover .. then nothing else gets triggered.... very annoying...more details see http://sitr.us/2011/07/28/how-mobile-safari-emulates-mouse-events.html
you can use both in one component (w.r.t react)
for eg:
<component onMouseMove={handleMouseMove} onTouchMove={handleMouseMove} />
on the bases of screen which is being used react will automatically switch either option of mouse or touch
or you can also use
("ontouchstart" in document.documentElement)
it gives true for touch screen device and vice versa
ref: https://codepen.io/tteske/pen/KKwxOxp

Extend jQuery's .on() to work with mobile touch events

I am attempting to use the jQuery mobile events without the rest of jQuery mobile.
https://github.com/jvduf/jquery-mobile-events/blob/master/jquery.mobile.events.js
That snippet enables them all, and works fine, but not with the .on() event handler. E.g:
$('a').on('tap',function(){
console.log('Hi there!');
});
However it does work with .live(), but that is now depreciated.
So my question; is there a a way to extend the .on() functionality to include the tap event and others? Full list below:
touchstart
touchmove
touchend
orientationchange
tap
taphold
swipe
swipeleft
swiperight
scrollstart
scrollstop
Thanks :)
However it does work with .live(), but that is now depreciated.
So I take it that you want to use event delegation to preserve those events on replaced elements. That would mean that this:
$('a').on('tap',function () {
console.log('Hi there!');
});
would need to change to something like:
$(document).on('tap', 'a', function () {
console.log('Hi there!');
});
in order for it to behave the same as $("a").live("tap", ...
Maybe it should be better to extend the JQuery event code for mobile and desktop.
One way to do this is to use the JQuery vmouse (virtual mouse) plugin.
From vmouse plugin comments:
// This plugin is an experiment for abstracting away the touch and mouse
// events so that developers don't have to worry about which method of input
// the device their document is loaded on supports.
//
// The idea here is to allow the developer to register listeners for the
// basic mouse events, such as mousedown, mousemove, mouseup, and click,
// and the plugin will take care of registering the correct listeners
// behind the scenes to invoke the listener at the fastest possible time
// for that device, while still retaining the order of event firing in
// the traditional mouse environment, should multiple handlers be registered
// on the same element for different events.
//
// The current version exposes the following virtual events to jQuery bind methods:
// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
For a better explanation, see https://coderwall.com/p/bdxjzg
vmouse plugin: https://github.com/jquery/jquery-mobile/blob/master/js/jquery.mobile.vmouse.js
Also see this link about current state of (touch) events: http://blogs.adobe.com/adobeandjquery/2011/03/07/the-current-state-of-touch-events/

Preventing mouse emulation events (i.e. click) from touch events in Mobile Safari / iPhone using Javascript

In doing a single page Javascript app with interactive DOM elements I've found that the "mouseover-mousemove-mousedown-mouseup-click" sequence happens all in a bunch after the "touchstart-touchmove-touchend" sequence of events.
I've also found that it is possible to prevent the "mouse*-click" events from happening by doing an "event.preventDefault()" during the touchstart event, but only then, and not during the touchmove and touchend. This is a strange design, because because it is not possible to know during the touchstart yet whether the user intents to drag or swipe or just tap/click on the item.
I ended up setting up a "ignore_next_click" flag somewhere tied to a timestamp, but this is obviously not very clean.
Does anybody know of a better way of doing this, or are we missing something?
Note that while a "click" can be recognized as a "touchstart-touchend" sequence (ie no "touchmove"), there are certain things, such as keyboard input focus, that can only happen during a proper click event.
Just prevent the touchend event. It will let the browser scroll the page when you touch the element but won't let it emit artificial mouse events.
element.addEventListener('touchend', event => {
event.preventDefault();
});
I've run into similar problems making cross-platform HTML5/JS apps. The only real answer for me was to preventDefault on the touch events, and actually manage the touch states and fire click, drags, etc. events on my own according to my logic. This sounds much much more daunting than it really is, but the mimicked click/mouse events work perfectly on most mobile browsers.
Click and the extra mouse sequence are all there for your convenience (and compatibility). My rule of thumb- if it's for your convenience but it's inconvenient, best kill it.
As far as the input boxes, they only need the touchend events. I've killed click/mouse events and was still able to let mobile browsers respond correctly to touches on inputs. If it's still giving you issues, you can modify the event handler to only supress events on non-inputs:
function touchHandler(event) {
var shouldIgnore = event.target != null
&& ( event.target.tagName.toLowerCase() == "input" || event.target.tagName.toLowerCase() == "textarea" );
if(!shouldIgnore) e.preventDefault();
}
I've made a solution myself, since I have not found a sufficient solution elsewhere:
var isTouch = ('ontouchstart' in window);
function kill(type){
window.document.body.addEventListener(type, function(e){
e.preventDefault();
e.stopPropagation();
return false;
}, true);
}
if( isTouch ){
kill('mousedown');
kill('mouseup');
kill('click');
kill('mousemove');
}
The check of isTouch lets things work as normal on mouse-input devices but kills the emulated events on Safari/iOS. The trick is to use useCapture = true in the call to addEventListener so we scoop up all the mouse events in the page without hacking the code all over the web app. See the docs for the function here: https://developer.mozilla.org/en-US/docs/DOM/EventTarget.addEventListener?redirectlocale=en-US&redirectslug=DOM%2Felement.addEventListener
Edit:
Now that libraries for handling this issue are better, you can just use something like Fastclick as an alternative (https://github.com/ftlabs/fastclick).
If you have to support devices which support both mouse and touch, another solution is to use a capture event listener which stops all mouse events which occur either
within a delay after the touch event
at the same position as the touch event
on the same target element as the touch event
The information (time, position or target element) of the touch event can be recorded in another capture event listener.
Wrapping your mouse-only code in a Window.matchesMedia function is the cleanest way I found.
if (window.matchMedia('(hover: hover), (any-hover: hover), (-moz-touch-enabled: 0)').matches) {
el.addEventListener('mouseover', ev => {
// mouse handler, no simulated hover
}
}
This works for preventing simulated hovers but will likely prevent simulated clicks, too.
Note: -moz-touch-enabled part required on Firefox as of version 58.
This solution allows you to listen for PointerEvents if they exist, followed by TouchEvents if they exist, followed by MouseEvents if neither of the other two exist. Mobile Safari will still raise both touchstart and mousedown, but you'll only be listening for touchstart.
if (window.PointerEvent) { /* decent browsers */
etouch.addEventListener('pointerdown', (e) => {
console.log('pointerdown');
});
}
else if (window.TouchEvent) { /* mobile Safari */
etouch.addEventListener('touchstart', (e) => {
console.log('touchstart');
});
}
else { /* desktop Safari */
etouch.addEventListener('mousedown', (e) => {
console.log('mousedown');
});
}
Using 'pointerwhatever' instead of 'mousewhatever' seems to work fine on current browsers (2019).
i.e. they invented a way of having the same code for all the entry devices.
Creating Fast Buttons for Mobile Web Applications has their solution to the problem.
Also beware that when using IE10 preventDefault() doesn't stop the ghost/synthetic/emulated mouse events after a MSPointerDown event, so a true cross-browser solution is harder.
You could try to quit the function on "click", "mousedown" or "mouseup" events when the device supports touch events.
use.addEventListener("click",function(e){
// EXIT FUNCTION IF DEVICE SUPPORTS TOUCH EVENTS
if ("ontouchstart" in document.documentElement) return false;
// YOURMOUSEONLY CODE HERE
});
Add an event listener to touchstart that adds attribute data-touched to the element. Add another event listener to click that checks for data-touched. If it's there, prevent default and remove it. Here's some JS from my implementation.
var menuLinks = document.querySelectorAll('#my-nav>li>a');
for (var i = 0; i < menuLinks.length; i++) {
var menuLink = menuLinks[i];
menuLink.addEventListener('touchstart', function () {
menuLink.setAttribute('data-touched', '');
});
menuLink.addEventListener('click', function (event) {
if (menuLink.hasAttribute('data-touched')) {
menuLink.removeAttribute('data-touched');
event.preventDefault();
}
});
pointer... events have a pointerType property that mouse... events lack. You can use this property to detect and ignore events that were generated by touch rather than by a mouse.
Before:
window.addEventListner('mousemove', (e) => {
/* No way to tell if this event came from a mouse or a finger */
console.log(':(');
});
After:
window.addEventListner('pointermove', (e) => {
if (e.pointerType !== 'mouse') return;
/* This event definitely came from a mouse */
console.log(':)');
});
You can take advantage of this property just by replacing your mouse... event listeners with pointer... listeners. pointer... events are well-supported in modern browsers (going back at least three years).

Categories

Resources