How to temporarily disable all event handlers attached to a control - javascript

Is there a way to do.
$("#controlId").suspendEvents();
$("#controlId").resumeEvents();
I'm aware of preventDefault and stopPropagation. I want to do from outside the event.
Please consider the following in your answer.
I cannot modify these bound events.
I do not know the bound events (Although it will be possible it will take me long time to do it). so it is not possible to .off() and then add them back one by one.

I was able to put together answers from 2 other questions.
1.Bind an event handler to front of the queue
2.Attach handler to all events in a control
The idea is to bind an event handler with e.stopImmediatePropagation to front of the queue for all events. It seems crude i would be glad if this can be improved.
The solution...
$.fn.preBind = function (type, data, fn) {
this.each(function () {
var $this = $(this);
$this.bind(type, data, fn);
$.each(type.split(/ +/), function () {
var currentBindings = $this.data('events')[this];
if ($.isArray(currentBindings)) {
currentBindings.unshift(currentBindings.pop());
}
});
});
return this;
};
$.fn.suspendEvents = function () {
this.preBind("click keydown keyup keypress mouseover mouseenter mouseout mouseleave mousedown mouseup mousemove change blur focus focusin focusout scroll resize load unload beforeunload", null, blockEvents);
}
$.fn.resumeEvents = function () {
var _this = this;
$.each("click keydown keyup keypress mouseover mouseenter mouseout mouseleave mousedown mouseup mousemove change blur focus focusin focusout scroll resize load unload beforeunload".split(/ +/), function () {
_this.unbind(this, blockEvents);
});
}
function blockEvents(e) {
e.stopImmediatePropagation();
}
Now i could use
$("#controlId").suspendEvents();
$("#controlId").resumeEvents();
EDIT: Modified resumeEvents() to overcome IE issue.

everything bubbles up, so catch any event in body and prevent them.
alternative
var myCtlrs = $("all i want").attr("disabled", disabled");
then
myCtlrs.removeAttr("disabled");

Related

what is the name of event?

i wanna make event when i click on element and move cursor to another element then release cursor.
i made it using mouseup and mousedown events.
but some time mouseup not work!!!
the cursor change to hand and cant release it on another element.
for(var i=0;i<20;i++) {
for(var j=0;j<20;j++) {
var circle = document.createElement("div");
circle.setAttribute("class","circle");
circle.setAttribute("id",20*(i-1)+j);
circle.setAttribute("style","left:"+(35*(j+1)+20*j)+"px;top:"+(10*(i+1)+20*i)+"px;");
circle.addEventListener("mouseup",function() { ...});
circle.addEventListener("mousedown",function() { ...});
body.appendChild(circle);
}
}
If you mousedown and then mousemove away from the element, the mouseup event never fires.
Try adding preventDefault() to your mousedown handler...
circle.addEventListener("mousedown",function(e) { e.preventDefault(); ... });
You may also try binding the mouseleave event to trigger the mouseup

How to set up touch and click events

I have a bunch of buttons with onclick handlers, which I want to behave differently when touched. From reading up on the topic, I have come up with this code:
var reds = document.getElementsByClassName('red');
for (var idx in reds) {
var element = reds[idx];
element.addEventListener('touchstart', function () {
element.addEventListener('touchend', function (event) {
alert('stuff');
event.preventDefault(); // we don't want the 'click' handler
});
element.addEventListener('touchmove', function (event) {
element.removeEventListener('touchend');
element.removeEventListener('touchmove');
});
});
}
The theory behind it being that when the user touches the button, I want to wait for him to also let go, if he instead moves(scrolls) the page, I want to ignore that action completely since it obviously was not meant as a 'click'. However, neither the touchend nor the touchmove events get fired, only the touchstart event. So is this setup unviable? What alternative could I use?

Order MouseUp Event

This is a theoretical question... I have two mouseUp events. One of them is fired from a external jQuery plugin developed by other people that I'm using, this event is bound in this way:
//Add Events for mouse drag / touch swipe action
$(document).bind(self.event_up + self.id, { self: self }, self.mouseUp);
The other mouse up event, it's fired by me, using the standard code, something like this:
$(document).mouseup(function (e) {
}
});
My question is easy, sometimes one event is fired before the other, and sometimes the other event is fired before the other one.
Can somebody explain me if I have any options to bind the mouseUp event in some order?
$(document).unbind('mouseup');
$(document).bind(
"mouseup",
function( event ){
event.stopPropagation();
$.externalFunction(event);
yourFunction(event)
}
);
This is what you need.

unbind all in event string using jQuery one()

I am checking for any interaction using JQuery's .one() function.
var myEvents = 'mousedown mousemove mouseup touchstart touchmove touchend mouseout';
jQuery(document).one(myEvents, function(){
//do something only once.
});
But I would like all these to be ubinded once any of these events has fired. I know I can unbind again with jQuery(document).unbind(myEvents), but was wondering if there was a clean inbuilt way of simply unbinding after one event.
EDIT: Here is a fiddle: http://jsfiddle.net/4HkQy/6/
You could extend jQuery with a function which serves exactly that purpose.
jQuery.fn.extend({
oneForAll: function(events, handler) {
var that = this,
oneForAll = function() {
that.unbind(events, oneForAll);
handler.apply(this, arguments);
};
that.on(events, oneForAll);
}
});
You would use it exactly the way you used one it would just be oneForAll.
JSFiddle: Demo
use .off()
jQuery(document).one('mousedown mousemove mouseup touchstart touchmove touchend mouseout', function (event) {
console.log(event.originalEvent.type);
jQuery('p').append(event.originalEvent.type);
//remove all handlers
jQuery(document).off('mousedown mousemove mouseup touchstart touchmove touchend mouseout');
});
But i would recommend using a namespaced handlers so that you won't remove any other event handlers by mistake.
jQuery(document).one('mousedown.myonce mousemove.myonce mouseup.myonce touchstart.myonce touchmove.myonce touchend.myonce mouseout.myonce', function (event) {
console.log(event.originalEvent.type);
jQuery('p').append(event.originalEvent.type);
//remove all handlers
jQuery(document).off('.myonce');
});
Demo: Fiddle

How to run a function only once when it's triggered by both focus and click events

I have an input element with 2 events attached: focus and click. They both fire off the same helper function.
When I tab to the input, the focus event fires and my helper is run once. No problems there.
When the element already has focus, and I click on it again, the click event fires and my helper runs once. No problems there either.
But when the element does not have focus, and I click on it, BOTH events fire, and my helper is run TWICE. How can I keep this helper only running once?
I saw a couple similar questions on here, but didn't really follow their answers. I also discovered the .live jQuery handler, which seems like it could work if I had it watch a status class. But seems like there should be a simpler way. The .one handler would work, except I need this to work more than once.
Thanks for any help!
The best answer here would be to come up with a design that isn't trying to trigger the same action on two different events that can both occur on the same user action, but since you haven't really explained the overall problem you're coding, we can't really help you with that approach.
One approach is to keep a single event from triggering the same thing twice is to "debounce" the function call and only call the function from a given element if it hasn't been called very recently (e.g. probably from the same user event). You can do this by recording the time of the last firing for this element and only call the function if the time has been longer than some value.
Here's one way you could do that:
function debounceMyFunction() {
var now = new Date().getTime();
var prevTime = $(this).data("prevActionTime");
$(this).data("prevActionTime", now);
// only call my function if we haven't just called it (within the last second)
if (!prevTime || now - prevTime > 1000) {
callMyFunction();
}
}
$(elem).focus(debounceMyFunction).click(debounceMyFunction);
This worked for me:
http://jsfiddle.net/cjmemay/zN8Ns/1/
$('.button').on('mousedown', function(){
$(this).data("mouseDown", true);
});
$('.button').on('mouseup', function(){
$(this).removeData("mouseDown");
});
$('.button').on('focus', function(){
if (!$(this).data("mouseDown"))
$(this).trigger('click.click');
});
$(".button").on('click.click',evHandler);
Which I stole directly from this:
https://stackoverflow.com/a/9440580/264498
You could use a timeout which get's cleared and set. This would introduce a slight delay but ensures only the last event is triggered.
$(function() {
$('#field').on('click focus', function() {
debounce(function() {
// Your code goes here.
console.log('event');
});
});
});
var debounceTimeout;
function debounce(callback) {
clearTimeout(debounceTimeout);
debounceTimeout = setTimeout(callback, 500);
}
Here's the fiddle http://jsfiddle.net/APEdu/
UPDATE
To address a comment elsewhere about use of a global, you could make the doubleBounceTimeout a collection of timeouts with a key passed in the event handler. Or you could pass the same timeout to any methods handling the same event. This way you could use the same method to handle this for any number of inputs.
Live demo (click).
I'm just simply setting a flag to gate off the click when the element is clicked the first time (focus given). Then, if the element gets focus from tabbing, the flag is also removed so that the first click will work.
var $foo = $('#foo');
var flag = 0;
$foo.click(function() {
if (flag) {
flag = 0;
return false;
}
console.log('clicked');
});
$foo.focus(function() {
flag = 1;
console.log('focused');
});
$(document).keyup(function(e) {
if (e.which === 9) {
var $focused = $('input:focus');
if ($focused.is($foo)) {
flag = 0;
}
}
});
It seems to me that you don't actually need the click handler. It sounds like this event is attached to an element which when clicked gains focus and fires the focus handler. So clicking it is always going to fire your focus handler, so you only need the focus handler.
If this is not the case then unfortunately no, there is no easy way to achieve what you are asking. Adding/removing a class on focus and only firing the click when the class isn't present is about the only way I can think of.
I have it - 2 options
1 - bind the click handler to the element in the focus callback
2 - bind the focus and the click handler to a different class, and use the focus callback to add the click class and use blur to remove the click class
Thanks for the great discussion everybody. Seems like the debouncing solution from #jfriend00, and the mousedown solution from Chris Meyers, are both decent ways to handle it.
I thought some more, and also came up with this solution:
// add focus event
$myInput.focus(function() {
myHelper();
// while focus is active, add click event
setTimeout(function() {
$myInput.click(function() {
myHelper();
});
}, 500); // slight delay seems to be required
});
// when we lose focus, unbind click event
$myInput.blur(function() {
$myInput.off('click');
});
But seems like those others are slightly more elegant. I especially like Chris' because it doesn't involve dealing with the timing.
Thanks again!!
Improving on #Christopher Meyers solution.
Some intro: Before the click event fires, 2 events are preceding it, mousedown & mouseup, if the mousedown is fired, we know that probably the mouseup will fire.
Therefore we probably wouldn't like that the focus event handler would execute its action. One scenario in which the mouseup wouldn't fire is if the user starts clicking the button then drags the cursor away, for that we use the blur event.
let mousedown = false;
const onMousedown = () => {
mousedown = true;
};
const onMouseup = () => {
mousedown = false;
// perform action
};
const onFocus = () => {
if (mousedown) return;
// perform action
};
const onBlur = () => {
mousedown = false;
// perform action if wanted
};
The following events would be attached:
const events = [
{ type: 'focus', handler: onFocus },
{ type: 'blur', handler: onBlur },
{ type: 'mousedown', handler: onMousedown },
{ type: 'mouseup', handler: onMouseup }
];

Categories

Resources