I love the new live event in jQuery 1.3. The question I have is the performance of this event. I know the advantages of using live over click/bind('click') but is there a performance hit for using it over click/bind('click')?
If not, why would you ever use click or bind('click')?
If not, why would you ever use click
or bind('click')?
Because $.live() has some significant disadvantages
Live events do not bubble in the traditional manner and cannot be
stopped using stopPropagation (This changed in jquery 1.4.4) or
stopImmediatePropagation. For example,
take the case of two click events -
one bound to "li" and another "li a".
Should a click occur on the inner
anchor BOTH events will be triggered.
This is because when a
$("li").bind("click", fn); is bound
you're actually saying "Whenever a
click event occurs on an LI element -
or inside an LI element - trigger this
click event." To stop further
processing for a live event, fn must
return false.
Live events currently only work when used against a selector. For
example, this would work: $("li
a").live(...) but this would not:
$("a", someElement).live(...) and
neither would this:
$("a").parent().live(...).
See this.
As for why you would ever use click or bind instead of live, the answer is because you don't need the extra functionality.
Related
Is it considered bad practice to use jQuery's .on() event handler for every event?
Previously, my code contained script like this:
$('#cartButton').click(function(){
openCart();
});
However I've recently started using InstantClick (a pjax jQuery plugin).
Now none of my scripts work. I understand why this is happening, but I cannot wrap my code with the InstantClick.on('change', function(){ tag as this means my code starts to repeat itself. For example, clicking on the cart button will run the openCart() function many times. So to get around this, I'm changing all my functions to something like this:
$(document).on('click', '#cartButton', function(){
openCart();
});
I'm curious as to whether this will increase loading times and cause excess strain. Is it bad practice to use the on() event handler for every event in my code?
It's not bad practice at all..
.on is the preferred method for handling all events, and using .click is just a shortcut that gets passed to the .on method anyway..
If you check out here (unminified source for jquery 2.1.0): https://code.jquery.com/jquery-2.1.0.js
Here are a couple notes:
search for this line: on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
This is the function definition for the on method and just shows you what the code is doing..
also search for this line: jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick "
Th code below this line is mapping all the directly callable shortcuts (like click) and shows you that they are just mapping to the 'on' method.
Hope this helps!!!
No it is not a bad practice to use .on(), actually if you check the source of the .click() function, you'll see that it actually calls .on().
But... Instead of creating an anonymous function, you should simply do this, which would be cleaner, and slightly faster:
$(document).on('click', '#cartButton', openCart);
and
$('#cartButton').click(openCart);
I am using jQuery v.1.7.1 where the .live() method is apparently deprecated.
The problem I am having is that when dynamically loading html into an element using:
$('#parent').load("http://...");
If I try and add a click event afterwards it does not register the event using either of these methods:
$('#parent').click(function() ...);
or
// according to documentation this should be used instead of .live()
$('#child').on('click', function() ...);
What is the correct way to achieve this functionality? It only seems to work with .live() for me, but I shouldn't be using that method. Note that #child is a dynamically loaded element.
Thanks.
If you want the click handler to work for an element that gets loaded dynamically, then you set the event handler on a parent object (that does not get loaded dynamically) and give it a selector that matches your dynamic object like this:
$('#parent').on("click", "#child", function() {});
The event handler will be attached to the #parent object and anytime a click event bubbles up to it that originated on #child, it will fire your click handler. This is called delegated event handling (the event handling is delegated to a parent object).
It's done this way because you can attach the event to the #parent object even when the #child object does not exist yet, but when it later exists and gets clicked on, the click event will bubble up to the #parent object, it will see that it originated on #child and there is an event handler for a click on #child and fire your event.
Try this:
$('#parent').on('click', '#child', function() {
// Code
});
From the $.on() documentation:
Event handlers are bound only to the currently selected elements; they
must exist on the page at the time your code makes the call to .on().
Your #child element doesn't exist when you call $.on() on it, so the event isn't bound (unlike $.live()). #parent, however, does exist, so binding the event to that is fine.
The second argument in my code above acts as a 'filter' to only trigger if the event bubbled up to #parent from #child.
$(document).on('click', '.selector', function() { /* do stuff */ });
EDIT: I'm providing a bit more information on how this works, because... words.
With this example, you are placing a listener on the entire document.
When you click on any element(s) matching .selector, the event bubbles up to the main document -- so long as there's no other listeners that call event.stopPropagation() method -- which would top the bubbling of an event to parent elements.
Instead of binding to a specific element or set of elements, you are listening for any events coming from elements that match the specified selector. This means you can create one listener, one time, that will automatically match currently existing elements as well as any dynamically added elements.
This is smart for a few reasons, including performance and memory utilization (in large scale applications)
EDIT:
Obviously, the closest parent element you can listen on is better, and you can use any element in place of document as long as the children you want to monitor events for are within that parent element... but that really does not have anything to do with the question.
The equivalent of .live() in 1.7 looks like this:
$(document).on('click', '#child', function() ...);
Basically, watch the document for click events and filter them for #child.
I know it's a little late for an answer, but I've created a polyfill for the .live() method. I've tested it in jQuery 1.11, and it seems to work pretty well. I know that we're supposed to implement the .on() method wherever possible, but in big projects, where it's not possible to convert all .live() calls to the equivalent .on() calls for whatever reason, the following might work:
if(jQuery && !jQuery.fn.live) {
jQuery.fn.live = function(evt, func) {
$('body').on(evt, this.selector, func);
}
}
Just include it after you load jQuery and before you call live().
.on() is for jQuery version 1.7 and above. If you have an older version, use this:
$("#SomeId").live("click",function(){
//do stuff;
});
I used 'live' in my project but one of my friend suggested that i should use 'on' instead of live.
And when i tried to use that i experienced a problem like you had.
On my pages i create buttons table rows and many dom stuff dynamically. but when i use on the magic disappeared.
The other solutions like use it like a child just calls your functions every time on every click.
But i find a way to make it happen again and here is the solution.
Write your code as:
function caller(){
$('.ObjectYouWntToCall').on("click", function() {...magic...});
}
Call caller(); after you create your object in the page like this.
$('<dom class="ObjectYouWntToCall">bla... bla...<dom>').appendTo("#whereeveryouwant");
caller();
By this way your function is called when it is supposed to not every click on the page.
I have something like:
function init(){
$('.btn').click(function(){
//do something;
}
}
And when new content is added via ajax, I'm calling init(), so that click event applies to new buttons. But when I click it once, it captures several clicks (as many times as I called init()). It makes sense, but how to avoid it?
jsFiddle link: http://jsfiddle.net/s2ZAz/8/
Solutions:
* Use $.delegate() - http://api.jquery.com/delegate/
* Use $.live() - http://api.jquery.com/live/
Less preferred, but still, solutions:
* Use $.off() - http://api.jquery.com/off/ or $.unbind() - http://api.jquery.com/unbind/
click says, "for every object matching the selector, hook up this click listener". You probably want something more like delegate that says "for every object that will ever match this selector, hook up this listener".
$(document).delegate('button', 'click', function() {
});
You will still get double callbacks if you call init twice, but in this manner, you won't have to call init twice, because as new objects are added, they'll already be assigned to click listeners.
Note that document above should be replaced with the nearest persistent ancestor, as per Greg's comment below.
Demo.
Since jQuery 1.7, you can preferably use the .on() function to achieve the same effect.
Demo.
You can use the unbind method to remove the event handler (or the off method if you're using the new jQuery 1.7 syntax for attaching handlers)
Better yet, you can use the live method, to set up the event handler for any elements that are added to the page in the future and match the given selector. In this way you only have to call init once.
$("body").delegate("button", "click", function() {
alert('I\'m annoying!');
});
$('div').append("<button>Click me, I will alert twice</button><br/>");
$('div').append("<button>Click me, I will alert once</button><br/>");
$('div').append("<button>Click me, I will not alert at all</button><br/>");
Try it out
As mentioned by David, and as per liho's delegate example (loved the way the fiddle cascaded how many times the alert would pop!!), the problem is with multiple bindings, which can be solved with .live() (deprecated) or .delegate() (being phased out), or .on() (the preferred). However, it is a mistake to delegate listening to the document or even body node in terms of performance.
A better way to do this is identify an ancestor of the button that will not ever be destroyed. body is an easy choice, but it's almost always the case that we build our pages with wrapper elements of some sort, which are nested one or more levels deeper than body and therefore allow you to set fewer listeners.
HTML:
<div id="someWrapper">
<div class="somethingThatGetsDestroyed">
<button>Click Me</button>
</div>
</div>
JS using jQuery 1.7+:
$('#someWrapper').on('click', 'button', function() {
alert('Clickity-click!');
});
What all events can be triggered programmatically using jQuery? Also is there any important differences to be remembered when one is doing event triggering using jQuery Vs a natural way of it being triggered?
Every event can be programmatically fired, just use the callback-less version of it.
Example:
$('#button').click(function() { alert('event hanlder'); });
$('#button').click(); // generate the event
About your second question, there should be no difference between the native and jQuery event handlers.
One thing that is neat though is that jQuery binds this to the element that received the event, inside the callback (this doesn't happen in native event handlers):
$('#button').click(function() { alert(this); }); // here 'this' == document.getElementById('button');
Warning: the element referenced by this is not "jQuery augmented". If you want to traverse or modify it with jQuery goodness you'll have to do something like var $this = $(this);
You should know the differences between trigger and triggerHandler in jQuery.
trigger
trigger attempts to replicate the natural event as best as it can. The event handler for the event being triggered get's executed, but the default browser actions will not always be replicated exactly. For example $('a#link).trigger('click'); will execute the javascript function bound to the links click event handler, but will not redirect the browser to the href of the anchor, like a normal click would. EX: http://jsfiddle.net/AxFkD/
All the short forms of the trigger call behave exactly like trigger IE. click(), mouseup(), keydown(), etc
triggerHandler
triggerHandler prevents bubbling up ( EX. http://jsfiddle.net/LmqsS/ ), it avoids default browser behaviour and just executes the events callback, and it returns the return value of the event handler instead of a jQUery object for chaining.
You should also be aware that trigger affects all elements matched by a selector, but triggerHandler only affects the first one EX: http://jsfiddle.net/jvnyS/
You can trigger any event programmatically. But most of the events cannot be simulated as the natural event using programmatic triggers.
//to trigger a click event on a button
$("buttonSelector").trigger("click");
First, for obvious reasons, you cannot trigger the ready event.
That said, events raised by trigger() behave the same way as if they were triggered by the user. In particular, the event handlers are called in the same order.
The only difference I know of is that triggered events did not bubble up the DOM tree in older versions of jQuery (that behavior was fixed in version 1.3).
I have read some post about why do not use jQuery.live() and I want to check if I got it:)
When I call $("body").delegate('element','click', function);
Is it the same as $(element).live('click', function) ?
In case of normal behaviour..According to the post there are some stopPropagation and performance boons, but is the main difference that live bind everytime to body element, while delegate can bind to another one?
One important difference is that ".live()" will actually build up the jQuery element list for the initial selector, even though the ".live()" function itself only needs the selector string. That means that if the selector is somewhat expensive, the code to set up the handler will go running all over the DOM for no good reason. The ".delegate()" call does not do that.
Really I don't see any reason that new code should use ".live()"; it was sort-of an architectural mistake and should eventually die quietly.
Nettuts has a screencast just to explain this: Quick Tip: The Difference Between Live() and Delegate()
Quote from the site:
// Live(), introduced in 1.3, allows for the binding
// of event handlers to all elements that match a
// selector, including those created in the future.
// It does this by attaching the handler to the document.
// Unfortunately, it does not work well with chaining.
// Don't expect to chain live() after calls like
// children().next()...etc.
$("li").live("click", function() {
$(this).parent().append("<li>New Element</li>");
});
// Delegate, new to version 1.4, perhaps should have been a complete
// replacement for Live(). However, that obviously
// would have broken a lot of code! Nonetheless,
// delegate remedies many of the short-comings
// found in live(). It attaches the event handler
// directly to the context, rather than the document.
// It also doesn't suffer from the chaining issues
// that live does. There are many performance benefits
// to using this method over live().
$('#items').delegate('li', 'click', function() {
$(this).parent().append('<li>New Element</li>');
});
is the main difference that live bind everytime to body element, while delegate can bind to another one?
Yes, exactly. Let's say you have a table that you add and remove rows from, and you want to handle clicks on those rows (or links or buttons within the rows). You could use live for that, but then the event has to bubble all the way down to the body level and let's face it, it feels a bit like a global variable. If you use delegate on the table element instead, you remain more targeted, isolated from other things going on on the page. delegate is a more modular, contained version of live.
Since the .live() method handles events once they have propagated to the top of the document, it is not possible to stop propagation of live events. Similarly, events handled by .delegate() will always propagate to the element to which they are delegated; event handlers on any elements below it will already have been executed by the time the delegated event handler is called.
The short of it is that .live runs at the document level and .delegate runs on whatever element you specify. Why does it make a difference? If you have a mousemove event (or several) bound using .live, jQuery will execute code every time you move your mouse anywhere on the page to see if your callback function should run. This is extremely inefficient and is the reason for having .delegate. .delegate functions only run when the even originates inside of the dom node you specify. If, for example, you said $('ul#myUL').delegate(...), then jQuery would only check to see if the code should run when the event originated from within ul#myUL