Live events in jQuery 1.7+ - javascript

I am trying to use the on method for future DOM elements, but for some reason instead of calling events on click, it fires them when the DOM objects are dynamically created.
here's the code that I have.
$("#checkbox1").on('click', toggleChecked(this.checked)); //this is included in Ajax call success method
function toggleChecked(status) {
$(".item").each(function () {
$(this).prop("checked", status);
});
}
What am I doing wrong here?

toggleChecked(this.checked) will right away execute the function and then on will get its return value as handler which is undefined.
Wrap it an anonymous function so that it will be called when you click on the checkbox.
$("#checkbox1").on('click', function(){
toggleChecked(this.checked)
});
If you use toggelChecked method directy as click handler you can get the checked status of the checkbox using `this.checked inside the handler.

Two problems:
By adding parenthesis, you are executing the function, you have to pass a reference to the function to .on()
You cannot pass parameters like you want to do. But this in the event handler will be the clicked DOMElement, so you can get the checked property value inside it with this.checked
Here's a modified code:
$("#checkbox1").on('click', toggleChecked);
function toggleChecked() {
// "this" here is the clicked element
var status = this.checked;
$(".item").each(function () {
// be careful in .each() 'this' is the currently iterated element
$(this).prop("checked", status);
});
}

You have to put the event listener within function literals. Otherwise, the function is directly called.
$("#checkbox1").on('click', function() {
toggleChecked(this.checked);
});
The function itself can be written more efficiently:
function toggleChecked(status) {
$(".item").prop("checked", status);
}

As people have pointed out, you are doing the function wrong (the function has to be an anonymous function or a pointer to a function, or string that points to a function). But you are also using 'on' method wrong, it is not exactly the same as the 'live' method. You watch the document (or an area of the document), and have a subselector in that.
$(document).on('click', "#checkbox1", function() {
var status = this.checked;
$(".item").each(function () {
$(this).prop("checked", status);
});
Note: If all your checkboxes are getting created in the 'checkBoxDiv' your selector can be:
$("#checkBoxDiv").on('click', "#checkbox1", ...
For more information about how to use 'on' see the comparison in functions in the 'live' documentation (about 1/3 of the way down the page).
From the documentation:
Rewriting the .live() method in terms of its successors is
straightforward; these are templates for equivalent calls for all
three event attachment methods:
$(selector).live(events, data, handler); // jQuery 1.3+
$(document).delegate(selector, events, data, handler); // jQuery
1.4.3+ $(document).on(events, selector, data, handler); // jQuery 1.7+
The events argument can either be a space-separated list of event type
names and optional namespaces, or an event-map of event names strings
and handlers. The data argument is optional and can be omitted. For
example, the following three method calls are functionally equivalent
(but see below for more effective and performant ways to attach
delegated event handlers):
$("a.offsite").live("click", function(){ alert("Goodbye!"); }); // jQuery 1.3+
$(document).delegate("a.offsite", "click", function(){ alert("Goodbye!"); }); // jQuery 1.4.3+
$(document).on("click", "a.offsite", function(){ alert("Goodbye!"); }); // jQuery 1.7+

Related

jQuery's One - Fire once with multiple event types

Is there a way to fire a single function once when any event is raised?
For example, if I have the following function: (demo in jsfiddle)
$('input').one('mouseup keyup', function(e){
console.log(e.type);
});
I'd like to only call the function once, regardless of which event fired it.
But according to the docs for .one():
If the first argument contains more than one space-separated event types, the event handler is called once for each event type.
So, currently the function will fire once for each event type.
Instead of using .one, use .on and remove the binding manually with .off.
$('input').on('mouseup keyup', function(e){
console.log(e.type);
$(this).off('mouseup keyup');
});
Fiddle: http://jsfiddle.net/23H7J/3/
This can be done a little more elegantly with namespaces:
$('input').on('mouseup.foo keyup.foo', function(e){
console.log(e.type);
$(this).off('.foo');
});
This allows us to use a single identifier (foo) to remove any number of bindings, and we won't affect any other mouseup or keyup bindings the element may have.
Fiddle: http://jsfiddle.net/23H7J/41/
Great answers! To wrap them into a function, here's a jQuery extension based off the current answers:
//The handler is executed at most once per element for all event types.
$.fn.once = function (events, callback) {
return this.each(function () {
$(this).on(events, myCallback);
function myCallback(e) {
$(this).off(events, myCallback);
callback.call(this, e);
}
});
};
Then call like this:
$('input').once('mouseup keyup', function(e){
console.log(e.type);
});
Demo in fiddle
Bonus: This has the added benefit of only detaching the handlers for this specific function by passing in the original handler to the off function. Otherwise, you'll need custom namespaces.
Additionally, if you want a handler to fire only once as soon as any of the elements fire any of the events and then immediately detach itself, then just remove the each from the extension like this:
//The handler is executed at most once for all elements for all event types.
$.fn.only = function (events, callback) {
var $this = $(this).on(events, myCallback);
function myCallback(e) {
$this.off(events, myCallback);
callback.call(this, e);
}
return this
};
To fire once and keep firing, the following snippet may be used:
https://jsfiddle.net/wo0r785t/1/
$.fn.onSingle = function(events, callback){
if ("function" == typeof(callback)) {
var t = this;
var internalCallback = function(event){
$(t).off(events, internalCallback);
callback.apply(t, [event]);
setTimeout(function(){
$(t).on(events, internalCallback);
}, 0);
};
$(t).on(events, internalCallback);
}
return $(this);
};
It works by temporarily disabling the events using the internalCallback function, and asynchronously (setTimeout) enabling it again.
Most other suggestions in this thread disable all future events on the target. However, while OP seems satisfied with previous answers, his question does not mention the permanent disabling of events.
You could just add $('input').off(); to the end of your function.
A simpler way to fire once but keep firing on subsequent changes, is to temporarily store the previous value and do a quick comparison: If nothing has changed then don't run the rest of the function.
jQUERY
$('input').on('keyup paste input change', function(e){
var oldValue = $(e.target).data('oldvalue');
var newValue = $(e.target).val();
if (oldValue === newValue) //nothing has changed
return;
$(e.target).data('oldvalue',newValue); //store the newly updated value
//proceed with the rest of the function
});
Note that I'm using .on to attach the events, instead of .one
PURE JAVASCRIPT
For a pure JavaScript solution, listeners need to be added separately, since it's not possible to pass multiple events to .addEventListener.
var selector = document.querySelector('input')
selector.addEventListener('keyup', updateElement);
selector.addEventListener('paste', updateElement);
selector.addEventListener('input', updateElement);
selector.addEventListener('change', updateElement);
function updateElement(e){
var oldValue = e.target.getAttribute('oldvalue');
var newValue = e.target.value;
if (oldValue === newValue) //nothing has changed
return;
console.log (newValue);
e.target.setAttribute('oldvalue', newValue); //store the newly updated value
//proceed with the rest of the function
}
Assuming you want to listen for changes in the input box, I suggest not to use mouseup to detect a possible Right click > paste, since the mouse could be released somewhere else, not necessarily inside the input box. To be on the safe side you better use keyup, paste, input and change, as I did on my code above.

Overriding jQuery event handlers

I am trying to override the default behavior of the jQuery event handlers. But can't seem to find any documentation on how to do this.
Say I'm binding a click handler to an element like this:
$('div#mydiv').on('click', funcName);
What I'm trying to accomplish is to overwrite the .on function, so I can modify the way any event is bound by jQuery
I've already tried overriding $.fn.on and that obviously caused a never ender loop:
$.fn.on = function(eventname, callback){
console.log(eventname + ' will be bound');
$(this).on(eventname, callback);
};
$(function(){
$('#element').on('click', function(){
console.log('Did execute click');
});
});
What is the proper way to hook into the event binding process? Also worth mentioning: I really just want to alter the way .on works, wrapping it into a different function wouldn't work for my case.
You need to cache the original function reference like so
var originalOn = jQuery.fn.on;
jQuery.fn.on = function() {
console.log(arguments[ 0 ] + ' will be bound');
originalOn.apply( this, arguments );
};
Here, we store the reference to jQuerys original .on function. Then we overwrite the handler, but we invoke the original function with the same context + arguments using Function.prototype.apply.

What is a proper way to add listeners to new elements after using AJAX to get the html content? (jQuery, Javascript)

I am making something that can loads new setting pages via AJAX, I am not sure what's the most efficient way to bind listeners to those elements from the new content page?
Here's my thought. I can make a function that compares file path, and for each condition, then I will apply correct listeners to those new elements based on what page that AJAX loaded. I feel like it will makes the function so big if I have a large amount of pages.
Thanks!
Two ways:
1) Bind on a non-dynamic parent container using .on()
$('.some-parent-class').on('click', '.element', function() {
// DO STUFF!
});
2) Bind the new elements after ajax call is completed
$.ajax(url, {
// ajax options
}).done( function(data) {
var newEl = $('<div class="element"></div>');
// Setup your newEl with data here...
newEl.on('click', function() {
// do stuff
});
newEl.appendTo($('.some-parent-class'));
});
The former usually results in quicker ajax response times, but may also slow click responsiveness down.
Use jQuery's .on() to handle event delegation. The first element you supply is a static element (never removed / replaced). the first argument is the event you wish to delegate against, mouseover/click, etc. The 2nd argument is the element we wish to have the event fire on when the event occurs. The 3rd argument is the callback, which is the function to run when the event fires.
$(document).on('event', 'elementIdentifier', function(){
//your code
});
$(".parent-div").on("click", ".child-div-class-name" ,function(){
somefunction();
});
all the new inserted elements inside the .parent-div will be having the listeners onclick
Adding on to Populus' answer, which is great as it is, a logically equivalent solution to his second option would be to use Promises:
var iGotYou = new Promise(function (res, rej) {
$.ajax({
//ajax paramaters
})
.done(function( data ) {
//handle the data as necessary...
//then resolve the Promise
res();
});
});
//the Promise has been resolved
iGotYou.then(function (response) {
//add the event listener now that the promise has been fulfilled
document.getElementById('someId').addEventListener('click', function (e) {
//whatever you want to do on click event
});
})
I'm not entirely sure what you're asking here, but you can use jQuery's .on() function to bind to elements that already exist in your document, OR elements that will exist in the future.
Here's a quick example:
$(document).ready(function () {
$(document).on('click', '#new-button', function() {
alert("You clicked the new button");
});
//get some HTML via ajax. Let's assume you're getting <button id="new-button">Click me</button>
$.get('url', function(res) {
$('body').append(res);
});
});

How to rebind the events in jquery

I have some events like click, dblclick that are attached on large number of elements. To unbind click and dblclick events with all the elements at once I used this in jquery :
$(document).unbind("click").unbind("dblclick");
Now I have to rebind these events to all the elements again. For this I used :
$(document).bind("click").bind("dblclick");
But this is not working. Events are not rebind. How can I do this?
$(document).bind("click").bind("dblclick");
I don't think this will bind anything, you need callbacks.
$(document).bind("click", onClick).bind("dblclick", onDbClick);
Also, in this case you might want to consider using namespaced events:
$(document).bind("click.myclick", onClick)
And then later unbind only this event, leaving the other click untouched.
$(document).unbind("click.myclick");
P.S. It's now considered better practice to use the new on, off methods for binding.
unbind:
$(document).off("click", myFunction);
bind:
$(document).on("click", myFunction);
function myFunction() {
alert('you clicked the document');
}
jQuery on() and off() would be the way to go, and when rebinding, the function would have to be passed in again, you can't just rebind and expect it to know what function to call.
The best way is to name the callback functions, just as #adeneo suggested. But sometimes you don’t know when the handlers are bound (f.ex in a plugin), or perhaps you added anonymous callbacks using something like:
$(document).click(function() {
// anonymous
});
then you can restore all those callbacks using the $._data object. Here is a function for you:
function restoreHandlers(elem, type) {
var orig = $._data(elem, 'events');
if ( type in orig ) {
return $.map(orig[type], function(o) {
return o.handler;
});
} else return [];
}
Use it like this (before you unbind):
var handlers = restoreHandlers(document, 'click');
then unbind:
$(document).off('click');
then rebind:
$.each(handlers, function(i, fn) {
$(document).on('click', fn);
});

What is difference between $(".anything").click() and $(".anything").bind(click)

What is difference between $(".anything").click() and $(".anything").bind(click)
$(".anything").click(function() {
});
$(".anything").bind('click', function() {
});
Nothing, click(function() { }) is just a shortcut for bind("click", function() { }).
From the jQuery docs:
The jQuery library provides shortcut methods for binding the standard event types, such as .click() for .bind('click').
You can read more about bind() here.
The first is a shortcut of the second. The second is actually wrong, click should have been quoted. Further, in the second you have the added benefit that you can bind the same function to multiple events, each separated by a space. E.g.
$(".anything").bind("click keypress blur", function() {
});
In that specific case, absolutely nothing.
However:
A) If you give .click() no argument, it triggers the event instead of setting the handler.
B) only .bind() lets you use the "namespaced" way of registering handlers:
$(whatever).bind('click.myEvent', function (e) { ... });
$(whatever).unbind('click.myEvent'); // Removes just that handler
See this post, which points to the JQuery source to show that .click(fn) just calls .bind('click', fn): jQuery: $().click(fn) vs. $().bind('click',fn);
I usually only use the latter if:
I want to bind multiple things, i.e. .bind('click focus', fn)
Just to maintain convention if I call unbind later, i.e.:
var fn = function() { alert('foo'); }
$('#foo').bind('click', fn);
...
$('#foo').unbind('click', fn);

Categories