I'm looking for the best solution to adding both "doubletap" and "longtap" events for use with jQuery's live(), bind() and trigger(). I rolled my own quick solution, but it's a little buggy. Does anyone have plugins they would recommend, or implentations of their own they'd like to share?
It has been reported to jQuery as a bug, but as doubletapping isn't the same as doubleclicking, it does not have a high priority. However, mastermind Raul Sanchez coded a jquery solution for doubletap which you can probably use!
Here's the link, works on mobile Safari.
It's easy to use:
$('selector').doubletap(function() {});
-edit-
And there's a longtap plugin here! You can see a demo on your iPad or iPhone here.
rsplak's answer is good. I checked out that link and it does work well.
However, it only implements a doubletap jQuery function
I needed a custom doubletap event that I could bind/delegate to. i.e.
$('.myelement').bind('doubletap', function(event){
//...
});
This is more important if you're writing a backbone.js style app, where there is a lot of event binding going on.
So I took Raul Sanchez's work, and turned it into a "jQuery special event".
Have a look here: https://gist.github.com/1652946 Might be useful to someone.
Just use a multitouch JavaScript library like Hammer.js. Then you can write code like:
canvas
.hammer({prevent_default: true})
.bind('doubletap', function(e) { // Also fires on double click
// Generate a pony
})
.bind('hold', function(e) {
// Generate a unicorn
});
It supports tap, double tap, swipe, hold, transform (i.e., pinch) and drag. The touch events also fire when equivalent mouse actions happen, so you don't need to write two sets of event handlers. Oh, and you need the jQuery plugin if you want to be able to write in the jQueryish way as I did.
I wrote a very similar answer to this question because it's also very popular but not very well answered.
You can also use jQuery Finger which also supports event delegation:
For longtap:
// direct event
$('selector').on('press', function() { /* handle event */ });
// delegated event
$('ancestor').on('press', 'selector', function() { /* handle event */ });
For double tap:
// direct event
$('selector').on('doubletap', function() { /* handle event */ });
// delegated event
$('ancestor').on('doubletap', 'selector', function() { /* handle event */ });
Here's a pretty basic outline of a function you can extend upon for the longtap:
$('#myDiv').mousedown(function() {
var d = new Date;
a = d.getTime();
});
$('#myDiv').mouseup(function() {
var d = new Date;
b = d.getTime();
if (b-a > 500) {
alert('This has been a longtouch!');
}
});
The length of time can be defined by the if block in the mouseup function. This probably could be beefed up upon a good deal. I have a jsFiddle set up for those who want to play with it.
EDIT: I just realized that this depends on mousedown and mouseup being fired with finger touches. If that isn't the case, then substitute whatever the appropriate method is... I'm not that familiar with mobile development.
based on latest jquery docs i've written doubletap event
https://gist.github.com/attenzione/7098476
function itemTapEvent(event) {
if (event.type == 'touchend') {
var lastTouch = $(this).data('lastTouch') || {lastTime: 0},
now = event.timeStamp,
delta = now - lastTouch.lastTime;
if ( delta > 20 && delta < 250 ) {
if (lastTouch.timerEv)
clearTimeout(lastTouch.timerEv);
return;
} else
$(this).data('lastTouch', {lastTime: now});
$(this).data('lastTouch')['timerEv'] = setTimeout(function() {
$(this).trigger('touchend');
}, 250);
}
}
$('selector').bind('touchend', itemTapEvent);
Related
I have a slider that I am currently making. I am making slow progress, but I am making progress nonetheless!
Currently I have this:
http://codepen.io/r3plica/pen/mEKyGG?editors=1011#0
There are 2 things you can do with this control, the first thing is you can drag left or right. The second thing you can do is click a "point" and it will scroll to the center.
The problem I have is that if I start dragging from a point, when I let go it will invoke the moveToCenter method.
I have tried to prevent this by adding
// Stop from accessing any child events
e.preventDefault();
e.stopPropagation();
to the end of the dragEventHandler, but this did not work.
I also have 2 boolean values options.drag and options.start. I though I might be able to use them somehow (if the drag has started and is enabled then don't perform the moveToCenter but this didn't work either.
Do anyone have any idea how to get this to work?
Maybe this will help. You can register your events in bubbling or capturing mode, using addEventListener method. It defines orders of processing your events - child -> parent (bubbling), or vice versa (capturing).
http://www.quirksmode.org/js/events_advanced.html
So, if you use addEventListener(event, handler, true), it will use capturing event mode.
Codepen:
http://codepen.io/anon/pen/bZKdqV?editors=1011
divs.forEach(function (div) {
div.addEventListener('click', function(e) {
e.stopPropagation();
console.log('parent');
}, true);
});
Be aware of browser support (IE9+). All modern browsers - yes, of course.
http://caniuse.com/#search=addeventlistener
Update
So it turned out to be easier than first approach. (no need for capturing)
Check out codepen:
http://codepen.io/anon/pen/QExjzV?editors=1010
Changes from your sample:
At the beginning of moveToCenter: function(e, options, animate) function
if (options.started) {
return;
}
In if (['mouseup', 'mouseleave'].indexOf(e.type) > -1):
setTimeout(function() {
options.started = false;
} , 100);
instead of
options.started = false;
Hope this helps.
I played around with a webdesign where jQuery is available. There is now a point where I need the opposite Eventwatching, so I realized it already with a jQuery routine which installs an "onnomousemove" event. Yes, you read correct, an NOT HAPPENING EVENT.
(Below) you find my allready working solution in jQuery. The idea is to have control over not happening Events and to react on that via this extra specified jQuery.Event
Hehe, I know most stupid would be to handle "onnoerror" Events with this. But thats not desired. Its working now and I want to go a step forward here. So what is my problem?
Here it comes: How to fire the same behavior with native Javascript EventListening so element.addEventListener(...); can handle the same Events too?
Problem: newer Web browser like Chrome, Firefox have an implemented CustomEvent handling to make this happen, but in older browsers there should be a way with prototype or so.
I'm a bit jQuery blind now, anyway is there somebody out there who knows the freaky trick to generate Custom Events in a traditional way without prototype.js or other libraries? Even a solution with jQuery would be fine, but desired goal is the native listener should be able to handle it.
jQuery:
(function($){
$.fn.extend({
// extends jQuery with the opposite Event Listener
onno:function(eventname,t,fn){
var onnotimer = null;
var jqueryevent = {};
$(this).on( eventname, function(e){
window.clearTimeout(onnotimer);
function OnNoEventFn(){
jqueryevent = jQuery.Event( "onno"+eventname );
$(this).trigger(jqueryevent);
e.timeStampVision=e.timeStamp+t;
e.timer=t; e.type="onno"+eventname;
fn(e);
}
onnotimer = window.setTimeout( OnNoEventFn, t);
});
return $(this);
}
});
})(jQuery);
$(document).ready(function() {
// installs "onnomousemove" and fires after 5sec if mousemove does not happen.
$(window).onno('mousemove', 5000, function(e){
console.log('function fires after:'+e.timer+'ms at:'+e.timeStampVision+'ms with:"'+e.type+'" event, exact fired:', e.timeStamp);
});
// installs "onnoclick" and fires after 4sec if click does not happen.
$(window).onno('click', 4000, function(e){
console.log('function fires after:'+e.timer+'ms at:'+e.timeStampVision+'ms with:"'+e.type+'" event, exact fired:', e.timeStamp);
});
// just for demonstration, routine with "onno.." eventnamescheme
$(window).on('onnomousemove',function(e){
console.log( 'tadaaaa: "'+e.type+'" works! with jQuery Event',e);
});
// same for "onnoclick"
$(window).on('onnoclick',function(e){
console.log( 'tadaaaa: "'+e.type+'" works! with jQuery Event',e);
});
});
// but how to install Custom Events even in older Safari ?
// newer Chrome, Firefox & Opera have CustomEvent.
window.addEventListener('onnomousemove',function(e){
console.log('native js is watching you',e);
},false);
I'm using the excellent jQuery knob plugin. However, I need to dynamically enable/disable the element depending on user input. There is support for having a disabled state on page load which have the effect that no mouse (or touch) events are bound to the canvas element. Does anyone know how to resolve this issue, that is, how to (after page load) bind and unbind these mouse event listeners?
Ideally I would like to do something like this (on a disabled knob)
$('.button').click(function() {
$('.knob').enable();
});
Edit:
I ended up rewriting the source which binds/unbinds the mouse and touch events. The solution is not perfect so I leave the question open if someone perhaps have a better (cleaner) solution.
html
<input class="knobSlider" data-readOnly="true">
<button id="testBtn">clickHere</button>
script
in doc ready,
$(".knobSlider").knob();
$("#testBtn").click(function(){
$(".knobSlider").siblings("canvas").remove();
if($(".knobSlider").attr("data-readOnly")=='true'){
$(".knobSlider").unwrap().removeAttr("data-readOnly readonly").data("kontroled","").data("readonly",false).knob();
}
else{
$(".knobSlider").unwrap().attr("data-readOnly",true).data("kontroled","").data("readonly",true).knob();
}
});
For reference you can use my jsfiddle link > http://jsfiddle.net/EG4QM/ (check this in firefox, because of some external resource load problem in chrome)
If someone doesn't like how the accepted answer destroys and recreates the internal canvas element, then checkout my approach:
https://jsfiddle.net/604kj5g5/1/
Essentially, check the draw() implementation (I also recommend listening on value changes in the draw method instead of the change and release, which work for and click and mousewheel events respectively, which imo is inconvenient).
var $input = $("input");
var knobEnabled = true;
var knobPreviousValue = $input.val();
$input.knob({
draw: function () {
if (knobPreviousValue === $input.val()) {
return;
}
if (!knobEnabled) {
$input.val(knobPreviousValue).trigger("change");
return;
}
knobPreviousValue = $input.val();
console.log($input.val());
},
});
Try this to disable the control.
I'm still trying to find a way to enable it back
$("#btnDisable").click(function(){
$("#knob").off().prev().off();
});
I stuck here with a little problem I have put pretty much time in which is pretty bad compared to its functionality.
I have tags in my DOM, and I have been binding several events to them with jQuery..
var a = $('<a>').click(data, function() { ... })
Sometimes I would like to disable some of these elements, which means I add a CSS-Class 'disabled' to it and I'd like to remove all events, so no events are triggered at all anymore. I have created a class here called "Button" to solve that
var button = new Button(a)
button.disable()
I can remove all events from a jQuery object with $.unbind. But I would also like to have the opposite feature
button.enable()
which binds all events with all handlers back to the element
OR
maybe there is a feature in jQuery that actually nows how to do that?!
My Button Class looks something similar to this:
Button = function(obj) {
this.element = obj
this.events = null
this.enable = function() {
this.element.removeClass('disabled')
obj.data('events', this.events)
return this
}
this.disable = function() {
this.element.addClass('disabled')
this.events = obj.data('events')
return this
}
}
Any ideas? Especially this rebind functionality must be available after disable -> enable
var a = $('<a>').click(data, function() { ... })
I found these sources that did not work for me:
http://jquery-howto.blogspot.com/2008/12/how-to-disableenable-element-with.html
http://forum.jquery.com/topic/jquery-temporarily-disabling-events
-> I am not setting the events within the button class
Appreciate your help.
$("a").click(function(event) {
event.preventDefault();
event.stopPropagation();
return false;
});
Returning false is very important.
Or you could write your own enable and disable functions that do something like:
function enable(element, event, eventHandler) {
if(element.data()[event].eventHandler && !eventHandler) { //this is pseudo code to check for null and undefined, you should also perform type checking
element.bind(event, element.data()[event]);
}
else (!element.data()[event] && eventHandler) {
element.bind(event, element.data()[event]);
element.data({event: eventHandler}); //We save the event handler for future enable() calls
}
}
function disable(element, event) {
element.unbind().die();
}
This isn't perfect code, but I'm sure you get the basic idea. Restore the old event handler from the element DOM data when calling enable. The downside is that you will have to use enable() to add any event listener that may need to be disable() d. Otherwise the event handler won't get saved in the DOM data and can't be restored with enable() again. Currently, there's no foolproof way to get a list of all event listeners on an element; this would make the job much easier.
I would go on this with different approach:
<a id="link1">Test function</a>
<a id="link2">Disable/enable function</a>
<script type="text/javascript">
$(function() {
// this needs to be placed before function you want to control with disabled flag
$("#link1").click(function(event) {
console.log("Fired event 1");
if ($(this).hasClass('disabled')) {
event.stopImmediatePropagation();
}
});
$("#link1").click(function() {
console.log("Fired event 2");
});
$("#link2").click(function() {
$("#link1").toggleClass("disabled");
});
});
</script>
This may not be what you require, since it may effect also other functions binded into this event later. The alternative may be to modify the functions itself to be more like:
$("#link1").click(function(event) {
console.log("Fired event 1");
if ($(this).hasClass('disabled')) {
return;
}
// do something here
});
if that is an option.
Instead of adding event handler to each element separately, you should use event delegation. It would make much more manageable structure.
http://www.sitepoint.com/javascript-event-delegation-is-easier-than-you-think/
http://cherny.com/webdev/70/javascript-event-delegation-and-event-hanlders
http://brandonaaron.net/blog/2010/03/4/event-delegation-with-jquery
This why you can just check for class(es) on clicked element , and act accordingly. And you will be able even to re-eanble them , jsut by changing the classes of a tag.
P.S. read the links carefully, so that you can explain it to others later. Event delegation is a very important technique.
You could use an <input type="button"> and then use $("#buttonID").addAttr('disabled', 'disabled'); and $("#buttonID").removeAttr('disabled');. Disabling and enabling will be handled by the browser. You can still restyle it to look like an anchor, if you need that, by removing backgrounds and borders for the button. Be aware though, that some margins and padding might still bugger u in some browsers.
I have a timed event I want to behave differently accordingly to what HTML element the mouse pointer is on.
Is there a way, assuming I have the HTML element, to know if the mouse pointer is currently on top of it.
I am well aware of the onmouseover/onmouseout events and how to use them.
I am using JQuery.
I am obviously looking for some kind of flag, as I need to check a state and not handle an event.
again, I know how to implement this with events.
I'm not aware of any built-in way to ping an element for the status of mouse hovering.
However, you can create one by updating a flag at mouseenter and mouseleave -- which is where Brian Driscoll's suggestion of .hover comes in:
jQuery.fn.tracking = function () {
this.data('hovering', false);
this.hover(function () {
$(this).data('hovering', true);
}, function () {
$(this).data('hovering', false);
});
return this;
};
jQuery.fn.hovering = function () {
return this.data('hovering');
}
You'll need to initialize tracking for each element you care about:
$('#elem1,#elem2').tracking();
But then you can get the status of any of them:
if ($('#elem1').hovering()) {
// ...
} else if ($('#elem2').hovering()) {
// ...
}
Demo: http://jsbin.com/amaxu3/edit
Have you looked into jQuery.hover()? http://api.jquery.com/hover/
You need to give name to html andme and on mouseover you need to check document.getelementsbyName. Then check what your are getting as output. Now you can take decision is it html control or asp.net.
When you use collObjects = object.getElementsByName("htmlcontrol") then compare id of both.
1 morething why you needed to check this in javascript. there may be some other solution for that. Just share with us.
You might have some luck with document.elementFromPoint, although I believe there are some inconsistencies in older browser implementations (http://www.quirksmode.org/dom/w3c_cssom.html#documentview).
$('#elem').mousemove(function(e){
if (this == document.elementFromPoint(e.clientX, e.clientY)) {
// Do stuff
}
});
Or outside of a handler
if ($('#elem').get(0) == document.elementFromPoint(x, y)) {
// Do stuff
}
Aside from that, the only other option that comes to mind is using event handlers to keep track of which element the mouse is over.