jQuery off then on chaining - javascript

I was wondering why this code would be effective, and if it is not, is there a better way to make sure that event handlers are removed before the new event handler is attached:
$('.selector')
.off('click', '.item')
.on('click', '.item', function() {
// code goes here
})
Thank you for help in knowing if this is an optimal way to make sure the event handler has been removed before adding another to the selector.

You can create a jQuery function that calls this two functions at once:
$.fn.onAndOff = function(event, selector, handler) {
this.off(event, selector)
.on(event, selector, handler);
}
Then use it like this:
$(".selector").onAndOff("click", ".item", function() {
// code goes here
});

If there's a risk of multiple identical click events being created for a particular element in your app, this may be a solution. Typically, however, the logic of your application is designed to prevent that.

Related

jQuery remove scroll listener after reach certain point [duplicate]

I have an input type="image". This acts like the cell notes in Microsoft Excel. If someone enters a number into the text box that this input-image is paired with, I setup an event handler for the input-image. Then when the user clicks the image, they get a little popup to add some notes to the data.
My problem is that when a user enters a zero into the text box, I need to disable the input-image's event handler. I have tried the following, but to no avail.
$('#myimage').click(function { return false; });
jQuery ≥ 1.7
With jQuery 1.7 onward the event API has been updated, .bind()/.unbind() are still available for backwards compatibility, but the preferred method is using the on()/off() functions. The below would now be,
$('#myimage').click(function() { return false; }); // Adds another click event
$('#myimage').off('click');
$('#myimage').on('click.mynamespace', function() { /* Do stuff */ });
$('#myimage').off('click.mynamespace');
jQuery < 1.7
In your example code you are simply adding another click event to the image, not overriding the previous one:
$('#myimage').click(function() { return false; }); // Adds another click event
Both click events will then get fired.
As people have said you can use unbind to remove all click events:
$('#myimage').unbind('click');
If you want to add a single event and then remove it (without removing any others that might have been added) then you can use event namespacing:
$('#myimage').bind('click.mynamespace', function() { /* Do stuff */ });
and to remove just your event:
$('#myimage').unbind('click.mynamespace');
This wasn't available when this question was answered, but you can also use the live() method to enable/disable events.
$('#myimage:not(.disabled)').live('click', myclickevent);
$('#mydisablebutton').click( function () { $('#myimage').addClass('disabled'); });
What will happen with this code is that when you click #mydisablebutton, it will add the class disabled to the #myimage element. This will make it so that the selector no longer matches the element and the event will not be fired until the 'disabled' class is removed making the .live() selector valid again.
This has other benefits by adding styling based on that class as well.
This can be done by using the unbind function.
$('#myimage').unbind('click');
You can add multiple event handlers to the same object and event in jquery. This means adding a new one doesn't replace the old ones.
There are several strategies for changing event handlers, such as event namespaces. There are some pages about this in the online docs.
Look at this question (that's how I learned of unbind). There is some useful description of these strategies in the answers.
How to read bound hover callback functions in jquery
If you want to respond to an event just one time, the following syntax should be really helpful:
$('.myLink').bind('click', function() {
//do some things
$(this).unbind('click', arguments.callee); //unbind *just this handler*
});
Using arguments.callee, we can ensure that the one specific anonymous-function handler is removed, and thus, have a single time handler for a given event. Hope this helps others.
maybe the unbind method will work for you
$("#myimage").unbind("click");
I had to set the event to null using the prop and the attr. I couldn't do it with one or the other. I also could not get .unbind to work. I am working on a TD element.
.prop("onclick", null).attr("onclick", null)
If event is attached this way, and the target is to be unattached:
$('#container').on('click','span',function(eo){
alert(1);
$(this).off(); //seams easy, but does not work
$('#container').off('click','span'); //clears click event for every span
$(this).on("click",function(){return false;}); //this works.
});​
You may be adding the onclick handler as inline markup:
<input id="addreport" type="button" value="Add New Report" onclick="openAdd()" />
If so, the jquery .off() or .unbind() won't work. You need to add the original event handler in jquery as well:
$("#addreport").on("click", "", function (e) {
openAdd();
});
Then the jquery has a reference to the event handler and can remove it:
$("#addreport").off("click")
VoidKing mentions this a little more obliquely in a comment above.
If you use $(document).on() to add a listener to a dynamically created element then you may have to use the following to remove it:
// add the listener
$(document).on('click','.element',function(){
// stuff
});
// remove the listener
$(document).off("click", ".element");
To remove ALL event-handlers, this is what worked for me:
To remove all event handlers mean to have the plain HTML structure without all the event handlers attached to the element and its child nodes. To do this, jQuery's clone() helped.
var original, clone;
// element with id my-div and its child nodes have some event-handlers
original = $('#my-div');
clone = original.clone();
//
original.replaceWith(clone);
With this, we'll have the clone in place of the original with no event-handlers on it.
Good Luck...
Updated for 2014
Using the latest version of jQuery, you're now able to unbind all events on a namespace by simply doing $( "#foo" ).off( ".myNamespace" );
Best way to remove inline onclick event is $(element).prop('onclick', null);
Thanks for the information. very helpful i used it for locking page interaction while in edit mode by another user. I used it in conjunction with ajaxComplete. Not necesarily the same behavior but somewhat similar.
function userPageLock(){
$("body").bind("ajaxComplete.lockpage", function(){
$("body").unbind("ajaxComplete.lockpage");
executePageLock();
});
};
function executePageLock(){
//do something
}
In case .on() method was previously used with particular selector, like in the following example:
$('body').on('click', '.dynamicTarget', function () {
// Code goes here
});
Both unbind() and .off() methods are not going to work.
However, .undelegate() method could be used to completely remove handler from the event for all elements which match the current selector:
$("body").undelegate(".dynamicTarget", "click")
I know this comes in late, but why not use plain JS to remove the event?
var myElement = document.getElementById("your_ID");
myElement.onclick = null;
or, if you use a named function as an event handler:
function eh(event){...}
var myElement = document.getElementById("your_ID");
myElement.addEventListener("click",eh); // add event handler
myElement.removeEventListener("click",eh); //remove it
This also works fine .Simple and easy.see http://jsfiddle.net/uZc8w/570/
$('#myimage').removeAttr("click");
if you set the onclick via html you need to removeAttr ($(this).removeAttr('onclick'))
if you set it via jquery (as the after the first click in my examples above) then you need to unbind($(this).unbind('click'))
All the approaches described did not work for me because I was adding the click event with on() to the document where the element was created at run-time:
$(document).on("click", ".button", function() {
doSomething();
});
My workaround:
As I could not unbind the ".button" class I just assigned another class to the button that had the same CSS styles. By doing so the live/on-event-handler ignored the click finally:
// prevent another click on the button by assigning another class
$(".button").attr("class","buttonOff");
Hope that helps.
Hope my below code explains all.
HTML:
(function($){
$("#btn_add").on("click",function(){
$("#btn_click").on("click",added_handler);
alert("Added new handler to button 1");
});
$("#btn_remove").on("click",function(){
$("#btn_click").off("click",added_handler);
alert("Removed new handler to button 1");
});
function fixed_handler(){
alert("Fixed handler");
}
function added_handler(){
alert("new handler");
}
$("#btn_click").on("click",fixed_handler);
$("#btn_fixed").on("click",fixed_handler);
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn_click">Button 1</button>
<button id="btn_add">Add Handler</button>
<button id="btn_remove">Remove Handler</button>
<button id="btn_fixed">Fixed Handler</button>
I had an interesting case relevant to this come up at work today where there was a scroll event handler for $(window).
// TO ELIMINATE THE RE-SELECTION AND
// RE-CREATION OF THE SAME OBJECT REDUNDANTLY IN THE FOLLOWING SNIPPETS
let $window = $(window);
$window.on('scroll', function() { .... });
But, to revoke that event handler, we can't just use
$window.off('scroll');
because there are likely other scroll event handlers on this very common target, and I'm not interested in hosing that other functionality (known or unknown) by turning off all of the scroll handlers.
My solution was to first abstract the handler functionality into a named function, and use that in the event listener setup.
function handleScrollingForXYZ() { ...... }
$window.on('scroll', handleScrollingForXYZ);
And then, conditionally, when we need to revoke that, I did this:
$window.off('scroll', $window, handleScrollingForXYZ);
The janky part is the 2nd parameter, which is redundantly selecting the original selector. But, the jquery documentation for .off() only provides one method signature for specifying the handler to remove, which requires this middle parameter to be
A selector which should match the one originally passed to .on() when attaching event handlers.
I haven't ventured to test it out with a null or '' as the 2nd parameter, but perhaps the redundant $window isn't necessary.

how to attach keyup event from within jQuery plugin

I have a jQuery plugin, and inside of it I have an init function. Inside of this init-function I attach some events:
(function ( $ ) {
$.fn.gallery = function(options) {
var init = function(self) {
var main += '<input id="gallery-search">';
//click event for the filter checkboxes
$("body").on('click', self.selector+" .gallery-filter-checkbox",function(event) {
self.data(filter( self ));
});
//capture input in the search box
$('#gallery-search').keyup(function(){
console.log('test');
});
self.html(output);
}
}( jQuery ));
}
The first one works just fine, but the second one doesn't work at all. I have tested it outside of the plugin scope and it works just fine so there is no syntax error, but probably an error in the way I try and attach the event?
Since #gallery-search is created dynamically, you can use delegated event handler:
$(document).on('keyup', '#gallery-search', function() { ... });
If self represents static HTML element at page, you can use a little better (for performance) version:
self.on('keyup', '#gallery-search', function() { ... });
Or you can place event handler in code after element's insertion, if HTML will not be modified later:
self.html(output);
$('#gallery-search').keyup(function()
{
console.log('test');
});
keyup() is a shortcut for bind('keyup',callback) which will register some event handler on the elements that are already present in the DOM (not necessarily rendered). It won't work if the element is not present in DOM when it's defined. To do that you need to use delegate() which will attach some handler on an element which is currently available or in might be available in future.
From jQuery 1.7 onwards, it's recommended to use on() as it combines the functionality of bind / delegate / live.
on() can be used in two ways
$(selector).on('event',callback);
$(parentSelector).on('event','someChildSelector', callback);
First one is direct handler and second one is called delegated handler.
If you're using first one to register event handlers, you've to make sure that element is present in the DOM at the time of registering just like bind(). So if you're adding new elements, you have to attach that handler again.
If you're using the second way, you don't have to worry about registering the handler again
$(document).on('click','.row',callback);
As document is always available, you callback will be registered as click handler for all the existing rows and any new row that you might add in the future.
I strongly recommend you read the Direct and delegated events section here. They even explain about the performance benefits.
Now that you know how it works, you can fix it using on() either as a direct handler or as a delegated handler.
EDIT : It's better to use closest static parent than document/body when using on() to register delegated handlers. Thanks to Regent for suggesting that :)
$('closestStaticParent').on('keyup','#gallery-search',function(){
console.log('test');
});

Javascript, jQuery - how signed actions to just created object?

I am trying to make simple list with ability to add and delete elements. For now I am working on adding and performing a simple action on each of list elements object (existing and added). Unfortunately I have met some difficulties with that. I am able to modify objects that are created at the beginning, but not one added during "webpage working".
First of all my idea was to add AJAX to this, but I don't think it is the easiest way.
I think that some time ago (I don't remember where) I read how to make this work, but now I don't know. I would be really glad if someone would help me with this or at least give a link to good explanation of this.
There is what I have done so far (well this is mostly just a scratch, but the main idea is in it): http://jsfiddle.net/sebap123/pAZ7H/0
$("li").click(function() {
$(this).text("new text");
});
$("#addButton").click(function() {
$(".list").append(
$('<li>').append($('<span>').append("added li")));
});​
Thank you for all responses.
You just need to use event-delegation, with the on() method:
$("ul").on('click','li', function() {
$(this).text("OK");
});
JS Fiddle demo.
The problem you were experiencing is that jQuery can only directly bind events to already-present elements (present at the point of event-binding); the on() approach binds the action to the element to which the new content is added (or an ancestor element of the newly-added elements), identifies the events to listen for 'click' (a space-separated list of events), that match the selector (li) and then the function performs the required actions.
If you're using jQuery 1.7 (or later) on() should be used, for versions of jQuery < 1.7, delegate() should be used instead (which does more or less the same thing, but reverses the event-list and the selector parameters):
$("ul").delegate('li', 'click', function() {
$(this).text("OK");
});
JS Fiddle demo.
References:
delegate().
on().
Need to use event delegation here..
Try this
$("ul").on('click' , 'li', function() {
$(this).text("OK");
});
The problem with the previous click event is that events are only attched to the current element's on the page..
But when you create a new element , no events are attached to the element.
You have two options here.. Either to delegate your event i.e; add the event listerner to the element's ancestor ..
Or add the event once the element is created..
2nd Approach
var clickEvent = function() {
$('li').unbind().on('click', function() {
$(this).text("OK");
});
}
clickEvent();
$("#addButton").click(function() {
$(".list").append(
$('<li>').append($('<span>').append("Press me - I am new!")));
clickEvent();
});​
In the second approach you are binding unbinding and binding the new event to all the elements once a new element is added..
Binding and again rebinding of events is a bad design pattern
FIDDLE
2nd APPROACH

How to make jQuery `bind` or `on` event handlers idempotent

Is there a way that I can call $(selector).bind('click', handler) or $(selector).on('click', handler) multiple times such that the handler only gets attached once?
Right now, I have multiple AJAX handlers with different success callbacks, each of which re-renders a different set of elements on the page. Ideally I'd like to refactor the "reattach events" routine to a single function rather than a routine for all.
The only way I can think of to do this right now is to explicitly unbind, for example:
$(selector).off('click');
$(selector).on('click', handler);
Looking for a way to do something like that automatically.
A better approach is just to move the .on call to a container. If you have a container, the .on sticks around and is applied to any existing or new children matching your selector:
$(container-selector).on("click", "element-selector", function(event){
// do stuff
});
http://api.jquery.com/on/
Cheers.
You can namespace your event handlers, and then just make sure you unbind before binding:
$('#something').unbind("click.some-feature").bind("click.some-feature", function() { ... });
You could write your own jQuery function to do that automatically:
$.fn.schneiderBind = function(name, fn) {
return this.unbind(name).bind(name, fn);
});
$('#something').schneiderBind("click", function() { ... });
Alternatively, you can use bubbling and delegation to bind higher in the DOM, at a point immune to dynamic updates.
$(document).on("click","selector", function() { code goes here... });
This will work with dynamically added objects

jquery functions dont work on dom elements loaded asynchromously

I wrote jQuery event handlers on DOM elements that are not yet in the page but might be loaded asynchronously into the page. What I observed was these event handlers seem to not recognize that some new elements were added to the DOM and that they need to act on them on triggering.
Am I right in my observation? How do I achieve this functionality?
If you want event handlers to work on dynamically added content, you need to use on
$(document).on("click", "someCssSelector", function(){
//your code here
});
Of course this will cause all clicks anywhere on your page to be watched. To be more efficient, see if you can structure your page so that all of these elements whose click event you want to handle will be in one container. ie, if all of these elements are going to be added to a div with an id of foo, you'd write the above more efficiently as
$("#foo").on("click", "someCssSelector", function(){
//your code here
});
If you're using jQuery < 1.7, you'd use delegate
$(document).delegate("someCssSelector", "click", function(){
//your code here
});
Am I right in my observation?
Yes.
How do I achieve this functionality?
Using the .on function to subscribe to those event handlers if you are using jQuery 1.7+:
$(document).on('click', '.someSelector', function() {
...
});
or using the .delegate function if you are using an older version (higher than 1.4.3):
$(document).delegate('.someSelector', 'click', function() {
...
});
For both you could use a more specific root than document to improve performance if you know that those elements will be added to some container for example.
And if you are using some prehistoric version you could go with .live():
$('.someSelector').live('click', function() {
...
});

Categories