Hammer.js : How to handle / set tap and doubletap on same elements - javascript

I'm using jquery.hammer.js, it works quite well and I am able to bind function to a doubletap event. That is working fine.
What I want is to bind two different behaviors. One for the "tap", one for the "doubletap". I use the code below to bind my functions. When I do that, I only get the "tap", the "doubletap" doesn't seem to be triggered.
$("#W0AM").hammer();
$("#W0AM").on('doubletap', function (event) {
alert( 'this was a double tap' );
}).on('tap', function (event) {
alert( 'this was a single tap' );
});
If I remove the .on('tap'... ) binding, then I get the "doubletap" as expected.
$("#W0AM").hammer();
$("#W0AM").on('doubletap', function (event) {
alert( 'this was a double tap' );
});
If I do the following, both events get triggered all the time. I mean, I tap and I see the alert for the tap and the double tap. I doubletap, same thing, I see both alerts.
$("#W0AM").hammer();
$("#W0AM").on('tap doubletap', function (event) {
alert( 'this was a ' + event.type );
});
The question is how can I bind both behavior and distinguish between the two in order to perform different things
Thank you.

Hammer.js now has a requireFailure method to recognize multiple taps.
Because multiple gestures can be recognized simultaneously and a gesture can be recognized based on the failure of other gestures. Multiple taps on the same element can be easily recognized on this way:
var hammer = new Hammer.Manager(el, {});
var singleTap = new Hammer.Tap({ event: 'singletap' });
var doubleTap = new Hammer.Tap({event: 'doubletap', taps: 2 });
var tripleTap = new Hammer.Tap({event: 'tripletap', taps: 3 });
hammer.add([tripleTap, doubleTap, singleTap]);
tripleTap.recognizeWith([doubleTap, singleTap]);
doubleTap.recognizeWith(singleTap);
doubleTap.requireFailure(tripleTap);
singleTap.requireFailure([tripleTap, doubleTap]);
When a tap gesture requires a failure to be recognized, its recognizer will wait a short period to check that the other gesture has been failed. In this case, you should not assume that its tap gesture event will be fired immediately.
SOURCE: http://hammerjs.github.io/require-failure/

While there's probably nothing wrong with the accepted answer, I personally had to edit it a little to get it working. Because this all took longer to discover than it should have I'll provide my working solution. But kudos to Josh Unger.
var hammer = new Hammer(document);
var singleTap = new Hammer.Tap({ event: "tap" });
var doubleTap = new Hammer.Tap({ event: "doubletap", taps: 2 });
hammer.add([doubleTap, singleTap]);
singleTap.requireFailure(doubleTap);
doubleTap.recognizeWith(singleTap);
hammer.on("tap", function(e) {console.log("tap");});
hammer.on("doubletap", function(e) {console.log("doubletap");});

My guess is that the alert is preventing doubletap from being triggered in the first code block... it's kinda messy but you could try something like:
var doubleTapped = false;
$("#W0AM").hammer();
$("#W0AM").on('doubletap', function (event) {
doubleTapped = true;
console.log( 'this was a double tap' );
}).on('tap', function (event) {
setTimeout(function() {
if(!doubleTapped) {
console.log( 'this was a single tap' );
}
doubleTapped = false;
}, 500); // This may have to be higher dependant on the speed of the double tap...
});

I'm using jQuery 2.1.0 and Hammer 1.0.10 and Chris's answer almost work but it fires logs tap after logging double tap. I've added a timeout also to the reset of doubleTap back to false and it seems to work out for me.
var doubleTapped = false;
Hammer(document.getElementById("W0AM")).on('doubletap', function (event) {
doubleTapped = true;
console.log( 'this was a double tap' );
}).on('tap', function (event) {
setTimeout(function() {
if(!doubleTapped) {
console.log( 'this was a single tap' );
}
setTimeout(function() {
doubleTapped = false;
}, 500);
}, 500); // This may have to be higher dependant on the speed of the double tap...
});

Related

Equivalent of "hold" and "release" in hammer.js 2.0

In hammer.js 1.1.3 version I was able to use the following code perfectly:
var button = Hammer(element, {
hold: true,
release: true
});
button .on('hold', function() {
//Do something when the hold event starts
});
button .on('release', function() {
//Do something when the hold event stops
});
But in hammer.js 2.0 I'm struggling to find an equivalent:
var button = new Hammer.Manager(element);
button.add(new Hammer.Press({
event: 'press',
pointer: 1,
threshold: 5,
time: 500
}));
button.on('press', function(event) {
//Do something when the the element is pressed after 500ms
});
//Possible handler when the element is released?
According to the documentation (http://hammerjs.github.io/getting-started.html) for the new hammer.js 2.0, there are 5 recognizers:
Pan, Pinch, Press, Rotate, Swipe, Tap
I couldn't find a appropriate recognizer that would allow release type functionality. Any thoughts, suggestions or ideas are appreciated. Cheers for reading!
This will be supported in the next release, 2.0.1!
https://github.com/hammerjs/hammer.js/commit/a764fde2e89c3af2575ae02d3af41d7787a60dc5
Managed to achieve this functionality using 'press' (hold) and 'pressup' (release)
var hammer = new Hammer(this);
hammer.on("press pressup", function (ev) {
// Hold gesture start (press)
if (ev.type == "press") {
console.log("Hold active");
}
// Hold gesture stop (pressup)
if (ev.type == "pressup") {
console.log("Hold inactive");
}
});
Tested on Hammer.JS v2.0.8
Using
$(button).on('touchend',function(e){});
Works on jQuery.

making my click double-click event working

Hi I am working on a click double-click event handler for my jquery ajax engine. The idea is that you can click or double-click a button. I wrote this myself but I don't see why it is not working.
this is the code:
$('body').on('click', '.double-click', function() {
var that = this;
var dblclick = $(that).data('clicks');
if(!dblclick){
dblclick = 0;
}
dblclick = dblclick + 1;
$(that).data('clicks', dblclick);
dblclick = $(that).data('clicks');
console.log('click - ' + dblclick);
if(dblclick > 1){
$(this).data('clicks', 0);
//ajaxloader(this, 1);
alert('dubbel-klik');
console.log('dubbelcik event');
}
setTimeout(function() {
if(dblclick == 1){
$(that).data('clicks', 0);
//ajaxloader(this, 0);
alert('klik');
console.log('single click event');
}
}, 400);
});
It maybe looks a little over complicated but that is because I tried out some stuff. The problem I have is that when I double-click the double click the single click gets also executed. How is this possible when I reset with $(this).data('clicks', 0);. Then the counter has to be 0 and the if statement in the timeout has to be false.
Someone knows what is going wrong!?
O yes see a working demo here: click the click en dubbelclick button
You're overcomplicating this. jQuery has all of this built-in:
$('body').on('click', function(){
alert("single click")
});
$('body').on('dblclick', function(){
alert("double click");
});
This will also click the single though: you might want to check out this thread to see what you could do to prevent that: Javascript with jQuery: Click and double click on same element, different effect, one disables the other

Capture "tap" event with pure JavaScript

How can I capture a user's "tap" event with pure JS? I cannot use any libraries, unfortunately.
The click event is triggered on mouse click as well as on a touch click.
The touchstart event is triggered when the screen is touched.
The touchend event is triggered when the touch ends. If the default action is prevented, a click event will not trigger.
http://www.w3.org/TR/touch-events/
There are touchstart, touchend and other events. You can add event listeners for them in this way:
var el = document.getElementById('test');
el.addEventListener('touchstart', touchHandler);
More information about native DOM events you can find on MDN webstite.
This is not my code but I can't remember where I got it from, used successfully. It uses jQuery but no extra libraries or plugins for the tap handling itself.
$.event.special.tap = {
setup: function(data, namespaces) {
var $elem = $(this);
$elem.bind('touchstart', $.event.special.tap.handler)
.bind('touchmove', $.event.special.tap.handler)
.bind('touchend', $.event.special.tap.handler);
},
teardown: function(namespaces) {
var $elem = $(this);
$elem.unbind('touchstart', $.event.special.tap.handler)
.unbind('touchmove', $.event.special.tap.handler)
.unbind('touchend', $.event.special.tap.handler);
},
handler: function(event) {
event.preventDefault();
var $elem = $(this);
$elem.data(event.type, 1);
if (event.type === 'touchend' && !$elem.data('touchmove')) {
event.type = 'tap';
$.event.handle.apply(this, arguments);
} else if ($elem.data('touchend')) {
$elem.removeData('touchstart touchmove touchend');
}
}
};
$('.thumb img').bind('tap', function() {
//bind tap event to an img tag with the class thumb
}
I used this for a project exclusively for iPad, so might need tweaking to work for desktop and tablet together.
I wrote a little script myself. It's not in pure-JS, but works fine for me.
It prevents executing the script on scrolling, meaning the script only fires on a 'tap'-event.
$(element)
.on('touchstart', function () {
$(this).data('moved', '0');
})
.on('touchmove', function () {
$(this).data('moved', '1');
})
.on('touchend', function () {
if($(this).data('moved') == 0){
// HERE YOUR CODE TO EXECUTE ON TAP-EVENT
}
});

What is the opposite of evt.preventDefault();

Once I've fired an evt.preventDefault(), how can I resume default actions again?
As per commented by #Prescott, the opposite of:
evt.preventDefault();
Could be:
Essentially equating to 'do default', since we're no longer preventing it.
Otherwise I'm inclined to point you to the answers provided by another comments and answers:
How to unbind a listener that is calling event.preventDefault() (using jQuery)?
How to reenable event.preventDefault?
Note that the second one has been accepted with an example solution, given by redsquare (posted here for a direct solution in case this isn't closed as duplicate):
$('form').submit( function(ev) {
ev.preventDefault();
//later you decide you want to submit
$(this).unbind('submit').submit()
});
function(evt) {evt.preventDefault();}
and its opposite
function(evt) {return true;}
cheers!
To process a command before continue a link from a click event in jQuery:
Eg: Click me
Prevent and follow through with jQuery:
$('a.myevent').click(function(event) {
event.preventDefault();
// Do my commands
if( myEventThingFirst() )
{
// then redirect to original location
window.location = this.href;
}
else
{
alert("Couldn't do my thing first");
}
});
Or simply run window.location = this.href; after the preventDefault();
OK ! it works for the click event :
$("#submit").click(function(event){
event.preventDefault();
// -> block the click of the sumbit ... do what you want
// the html click submit work now !
$("#submit").unbind('click').click();
});
event.preventDefault(); //or event.returnValue = false;
and its opposite(standard) :
event.returnValue = true;
source:
https://developer.mozilla.org/en-US/docs/Web/API/Event/returnValue
I had to delay a form submission in jQuery in order to execute an asynchronous call. Here's the simplified code...
$("$theform").submit(function(e) {
e.preventDefault();
var $this = $(this);
$.ajax('/path/to/script.php',
{
type: "POST",
data: { value: $("#input_control").val() }
}).done(function(response) {
$this.unbind('submit').submit();
});
});
I would suggest the following pattern:
document.getElementById("foo").onsubmit = function(e) {
if (document.getElementById("test").value == "test") {
return true;
} else {
e.preventDefault();
}
}
<form id="foo">
<input id="test"/>
<input type="submit"/>
</form>
...unless I'm missing something.
http://jsfiddle.net/DdvcX/
This is what I used to set it:
$("body").on('touchmove', function(e){
e.preventDefault();
});
And to undo it:
$("body").unbind("touchmove");
There is no opposite method of event.preventDefault() to understand why you first have to look into what event.preventDefault() does when you call it.
Underneath the hood, the functionality for preventDefault is essentially calling a return false which halts any further execution. If you’re familiar with the old ways of Javascript, it was once in fashion to use return false for canceling events on things like form submits and buttons using return true (before jQuery was even around).
As you probably might have already worked out based on the simple explanation above: the opposite of event.preventDefault() is nothing. You just don’t prevent the event, by default the browser will allow the event if you are not preventing it.
See below for an explanation:
;(function($, window, document, undefined)) {
$(function() {
// By default deny the submit
var allowSubmit = false;
$("#someform").on("submit", function(event) {
if (!allowSubmit) {
event.preventDefault();
// Your code logic in here (maybe form validation or something)
// Then you set allowSubmit to true so this code is bypassed
allowSubmit = true;
}
});
});
})(jQuery, window, document);
In the code above you will notice we are checking if allowSubmit is false. This means we will prevent our form from submitting using event.preventDefault and then we will do some validation logic and if we are happy, set allowSubmit to true.
This is really the only effective method of doing the opposite of event.preventDefault() – you can also try removing events as well which essentially would achieve the same thing.
Here's something useful...
First of all we'll click on the link , run some code, and than we'll perform default action. This will be possible using event.currentTarget Take a look. Here we'll gonna try to access Google on a new tab, but before we need to run some code.
Google
<script type="text/javascript">
$(document).ready(function() {
$("#link").click(function(e) {
// Prevent default action
e.preventDefault();
// Here you'll put your code, what you want to execute before default action
alert(123);
// Prevent infinite loop
$(this).unbind('click');
// Execute default action
e.currentTarget.click();
});
});
</script>
None of the solutions helped me here and I did this to solve my situation.
<a onclick="return clickEvent(event);" href="/contact-us">
And the function clickEvent(),
function clickEvent(event) {
event.preventDefault();
// do your thing here
// remove the onclick event trigger and continue with the event
event.target.parentElement.onclick = null;
event.target.parentElement.click();
}
I supose the "opposite" would be to simulate an event. You could use .createEvent()
Following Mozilla's example:
function simulateClick() {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent("click", true, true, window,
0, 0, 0, 0, 0, false, false, false, false, 0, null);
var cb = document.getElementById("checkbox");
var cancelled = !cb.dispatchEvent(evt);
if(cancelled) {
// A handler called preventDefault
alert("cancelled");
} else {
// None of the handlers called preventDefault
alert("not cancelled");
}
}
Ref: document.createEvent
jQuery has .trigger() so you can trigger events on elements -- sometimes useful.
$('#foo').bind('click', function() {
alert($(this).text());
});
$('#foo').trigger('click');
This is not a direct answer for the question but it may help someone. My point is you only call preventDefault() based on some conditions as there is no point of having an event if you call preventDefault() for all the cases. So having if conditions and calling preventDefault() only when the condition/s satisfied will work the function in usual way for the other cases.
$('.btnEdit').click(function(e) {
var status = $(this).closest('tr').find('td').eq(3).html().trim();
var tripId = $(this).attr('tripId');
if (status == 'Completed') {
e.preventDefault();
alert("You can't edit completed reservations");
} else if (tripId != '') {
e.preventDefault();
alert("You can't edit a reservation which is already attached to a trip");
}
//else it will continue as usual
});
jquery on() could be another solution to this. escpacially when it comes to the use of namespaces.
jquery on() is just the current way of binding events ( instead of bind() ). off() is to unbind these. and when you use a namespace, you can add and remove multiple different events.
$( selector ).on("submit.my-namespace", function( event ) {
//prevent the event
event.preventDefault();
//cache the selector
var $this = $(this);
if ( my_condition_is_true ) {
//when 'my_condition_is_true' is met, the binding is removed and the event is triggered again.
$this.off("submit.my-namespace").trigger("submit");
}
});
now with the use of namespace, you could add multiple of these events and are able to remove those, depending on your needs.. while submit might not be the best example, this might come in handy on a click or keypress or whatever..
you can use this after "preventDefault" method
//Here evt.target return default event (eg : defult url etc)
var defaultEvent=evt.target;
//Here we save default event ..
if("true")
{
//activate default event..
location.href(defaultEvent);
}
You can always use this attached to some click event in your script:
location.href = this.href;
example of usage is:
jQuery('a').click(function(e) {
location.href = this.href;
});
In a Synchronous flow, you call e.preventDefault() only when you need to:
a_link.addEventListener('click', (e) => {
if( conditionFailed ) {
e.preventDefault();
// return;
}
// continue with default behaviour i.e redirect to href
});
In an Asynchronous flow, you have many ways but one that is quite common is using window.location:
a_link.addEventListener('click', (e) => {
e.preventDefault(); // prevent default any way
const self = this;
call_returning_promise()
.then(res => {
if(res) {
window.location.replace( self.href );
}
});
});
You can for sure make the above flow synchronous by using async-await
this code worked for me to re-instantiate the event after i had used :
event.preventDefault(); to disable the event.
event.preventDefault = false;
I have used the following code. It works fine for me.
$('a').bind('click', function(e) {
e.stopPropagation();
});

Differentiate between focus event triggered by keyboard/mouse

I'm using jquery ui autocomplete and want to decipher between focus events triggered by keyboard interaction and mouse interaction. How would I go about this?
$('input').autocomplete({
source: function(request, response) {
...
},
focus: function(event, ui) {
// If focus triggered by keyboard interaction
alert('do something');
// If focus event triggered by mouse interaction
alert('do something else');
}
});
Thanks
The only way I can think of doing this is to have a handler listen in on the keypress and click events, and toggle a boolean flag on/off. Then on the focus handler of your input, you can just check what the value of your flag is, and go from there.
Probably something like
var isClick;
$(document).bind('click', function() { isClick = true; })
.bind('keypress', function() { isClick = false; })
;
var focusHandler = function () {
if (isClick) {
// clicky!
} else {
// tabby!
}
}
$('input').focus(function() {
// we set a small timeout to let the click / keypress event to trigger
// and update our boolean
setTimeout(focusHandler,100);
});
Whipped up a small working prototype on jsFiddle (don't you just love this site?). Check it out if you want.
Of course, this is all running off a focus event on an <input>, but the focus handler on the autocomplete works in the same way.
The setTimeout will introduce a bit of lag, but at 100ms, it might be negligible, based on your needs.
You should actually be able to determine this from the event-Object that is passed into the focus-event. Depending on your code structure this might be different, but there is usually a property called originalEvent in there, which might be nested to some depth. Examine the event-object more closely to determine the correct syntax. Then test on mousenter or keydown via regular expression. Something like this:
focus: function(event, ui){
if(/^key/.test(event.originalEvent.originalEvent.type)){
//code for keydown
}else{
//code for mouseenter and any other event
}
}
The easiest and most elegant way I've found of achieving this is to use the "What Input?" library. It's tiny (~2K minified), and gives you access to the event type both in scripts:
if (whatInput.ask() === 'mouse') {
// do something
}
...and also (via a single data attribute that it adds to the document body) styles:
[data-whatinput="mouse"] :focus,
[data-whatinput="touch"] :focus {
// focus styles for mouse and touch only
}
I particularly like the fact that where you just want a different visual behaviour for mouse / keyboard it makes it possible to do that in the stylesheet (where it really belongs) rather than via some hacky bit of event-checking Javascript (though of course if you do need to do something that's not just purely visual, the former approach lets you handle it in Javascript instead).
The first thing that comes to mind is that you can find the position of the mouse and check to see if its within the position of the element
Use this to store the position of the element:
var input = $('#your_autocompleted_element_id'),
offset = input.offset(),
input_x = offset.top,
input_y = offset.left,
input_w = input.outerWidth(),
input_h = input.outerHeight();
Then use this to find absolute position of the mouse within the window:
var cur_mx, cur_my;
$(document).mousemove(function(e){
cur_mx = e.pageX;
cur_my = e.pageY;
});
Then in your autcomplete setup:
focus: function(event, ui) {
// mouse is doing the focus when...
// mouse x is greater than input x and less than input x + input width
// and y is greater than input y and less than input y + input height
if (cur_mx >= input_x && cur_mx <= input_x + input_w && cur_my >= input_y && cur_my <= input_y + input_h) {
// do your silly mouse focus witchcraft here
} else {
// keyboard time!
}
}
This can be handled using mousedown event, see my example below.
this.focusFrom = 'keyboard' =>
onFocus = () => {
if (this.focusFrom === 'keyboard') {
// do something when focus from keyboard
}
}
handleMouseDown = () => {
this.focusFrom = 'mouse';
}
handleOnClick = () => {
this.focusFrom = 'keyboard';
}

Categories

Resources