I'm curious to know the differences between the bind and live functions.
To me they seem to be almost identical.
I read the benefits of live/bind methods, but it didn't tell me about the differences...
Thanks!
In short: .bind() will only apply to the items you currently have selected in your jQuery object. .live() will apply to all current matching elements, as well as any you might add in the future.
The underlying difference between them is that live() makes use of event bubbling. That is, when you click on a button, that button might exist in a <p>, in a <div>, in a <body> element; so in effect, you're actually clicking on all of those elements at the same time.
live() works by attaching your event handler to the document, not to the element. When you click on that button, as illustrated before, the document receives the same click event. It then looks back up the line of elements targeted by the event and checks to see if any of them match your query.
The outcome of this is twofold: firstly, it means that you don't have to continue reapplying events to new elements, since they'll be implicitly added when the event happens. However, more importantly (depending on your situation), it means that your code is much much lighter! If you have 50 <img> tags on the page and you run this code:
$('img').click(function() { /* doSomething */ });
...then that function is copied into each of those elements. However, if you had this code:
$('img').live('click', function() { /* doSomething */ });
...then that function is stored only in one place (on the document), and is applied to whatever matches your query at event time.
Because of this bubbling behaviour though, not all events can be handled this way. As Ichiban noted, these supported events are click, dblclick mousedown, mouseup, mousemove, mouseover, mouseout, keydown, keypress, keyup.
.bind() attacheds events to elements that exist or match the selector at the time the call is made. Any elements created afterwards or that match going forward because the class was changed, will not fire the bound event.
.live() works for existing and future matching elements. Before jQuery 1.4 this was limited to the following events: click, dblclick mousedown, mouseup, mousemove, mouseover, mouseout, keydown, keypress, keyup
Bind will bind events to the specified pattern, for all matches in the current DOM at the time you call it. Live will bind events to the specified pattern for the current DOM and to future matches in the DOM, even if it changes.
For example, if you bind $("div").bind("hover", ...) it will apply to all "div"s in the DOM at the time. If you then manipulate the DOM and add an extra "div", it won't have that hover event bound. Using live instead of bind would dispatch the event to the new div as well.
Nice read on this: http://www.alfajango.com/blog/the-difference-between-jquerys-bind-live-and-delegate/
Is nowadays (since jQuery 1.7) deprecated using the .on() function - http://api.jquery.com/on/
imagine this scenario:
i have several <img> elements.
$('img').bind('click', function(){...});
add some extra images (using get(), or html(), anything)
the new images don't have any binding!!
of course, since the new images didn't exist when you did the $('img')... at step 2, it didn't bind the event handler to them.
now, if you do this:
i have several <img> elements.
$('img').live('click', function(){...});
add some extra images (using get(), or html(), anything)
the new images do have the binding!!
magic? just a little. in fact jQuery binds a generic event handler to another element higher in the DOM tree (body? document? no idea) and lets the event bubble up. when it gets to the generic handler, it checks if it matches your live() events and if so, they're fired, no matter if the element was created before or after the live() call.
In adition to what they said, I think it's best to try to stick to bind when/where you can and use live only when you must.
All these jQuery methods are used for attaching events to selectors or elements. But they all are different from each other.
.bind(): This is the easiest and quick method to bind events. But the issue with bind() is that it doesn’t work for elements added dynamically that matches the same selector. bind() only attach events to the current elements not future element. Above that it also has performance issues when dealing with a large selection.
.live(): This method overcomes the disadvantage of bind(). It works for dynamically added elements or future elements. Because of its poor performance on large pages, this method is deprecated as of jQuery 1.7 and you should stop using it. Chaining is not properly supported using this method.
Find out more here
I wanted to add to this after having to debug a bit due to my own silliness. I applied .live() to a class of button on my page, assuming that it would just render out the correct ID I was trying to pass on the query string and do what I wanted to do with the ajax call. My app has dynamically added buttons associated with an inventory item. For instance, drill down categories to the 'COKE' button to add a coke to your order. Drill down from the top again, and add 'BUDLITE' - each time I wanted those items to be entered into a table via an AJAX call.
However, since I bound .live() to the entire class of buttons, it would remember each ajax call I had made and re-fire it for each subsequent button! It was a little tricky because I wasn't exactly clear on the difference between bind and live (and the answer above is crystal about it), so I figured I'd put this here just in case somebody was doing a search on this stuff.
There is a way to get the live effect but its kind of nasty.
$(this).unbind('mouseout').bind('mouseout',function(){
});
this will clear the previous and reset the new. It has seemed to work fine for me over time.
Difference between live and livequery is discussed here .
Related
I have some dynamic content that I am loading in via jQuery .load(). I have been trying to utilize the .on method, since the .live method is deprecated to bind elements to the page before they actually exist. I was able to achieve that but in this particular case the method I am invoking is firing twice. Any ideas and or solutions would be greatly appreciated.
I have tried unbinding('click') before binding and that seem to work but it causes the item I am trying to click on to fire on the second click. I also tried event.stopPropagation with no luck. Below is the code I currently have in place. I am currently utilizing the setTimeout approach until I can find a suitable solution.
$('#content').unbind('click').on('click', '.alternate-options', function(event){
//setTimeout(function(){
$('.alternate-option').each(function (index) {
$(this).bind('click', function (event) {
event.preventDefault();
$('.alternate-options li').each(function () {
$(this).removeClass('current');
});
$(this).addClass('current');
});
});
//},100);
});
Joel's answer is correct, but I thought it would be useful to explain it a little bit for others that might come across this in the future.
The deprecation of live() caused a lot of confusion for folks, but the replacement recommended technique really is a lot better once you understand it well.
First, the basics. If you're dynamically adding DOM elements to the page, you have to choose an approach to handling events on them.
One approach is to manually add event handlers to each element as they are dynamically added, typically you'd either add a data-* attribute to indicate the unique attribute of the dynamically added element, or you'd stick an object onto the DOM element itself that can be later retrieved in the event.
The old jquery approach let you simplify this process by using the live() API. In this case, you'd have a selector, and the DOM would be monitored for changes to that selector. This was pretty simple from the developer's perspective but had some major drawbacks. For more information this SO post describes some of the issues well: What's wrong with the jQuery live method?
The newer, and better approach is to use the on() method and look at a parent container DOM element, with an optional selector as a filter.
The reason why this works well is because it uses the normal DOM event bubbling behavior. When you trigger a bubbleable event (like click) on an element, that event will naturally "bubble" up the DOM, with a chance to catch it on each parent element all the way up the scene graph.
In the case of dynamic elements, this works really well. If you have a div, for example, that you're listening for a click event on, that event will be caught for any click events that were triggered by children, no mater when they were added to the DOM.
It would be a little annoying, however, to have to do a bunch of "if" statements inside of that click handler to determine if the element that was clicked was the one you're interested in. This is why the smart folks on the jquery team added the optional filter argument to the on() function. It let's you filter out events that were triggered by elements you don't care about.
This is why Joel's simple example works: you don't need to worry about directly adding event listeners to child elements or anything like that, you are just listening to the events on the container and filtering on the specific elements you care about.
This should do what you want it to:
$("#content").on("click", ".alternate-option li", function () {
$(".alternate-option li.current").removeClass("current");
$(this).addClass("current");
});
No need to rebind events or anything.
Here's a fiddle illustrating this binding with the dynamic content (both adding new list item or completely replacing the entire list):
http://jsfiddle.net/2jKCL/
I have a click event created by plugin and after I load $.ajax and only replaced(update) the area where contain the click event, the event will lost.
<span ref='B'><span ref='A'></span></span>
//click event is on A, but I replaced the html inside of B to <span ref='A'></span>;
its update, so the replaced html are the same.
I read many related problems, I found the solution are
.live() // will not work
.delegate(), // work
.on(), // work
The solution is I should bind the event on B instead of A like B.on('click', A, function(){})....
However, my structure is very hard to change, I rather want to find a solution that can prevent lose events while replacing or alternative.
Please advice, thank you very much.
Solved by using detach()
Since event bindings exist within the context of DOM elements, when you start removing or replacing DOM elements, you need some mechanism to re-establish the event bindings.
A good approach is to use delegation via a parent element (as you have stated - B.on('click', A, function(){}).... ).
The other alternative is to always re-establish the bindings at the point at which the DOM elements in question are removed or replaced (so in your scenario, it sounds like this would have to be in the Ajax callback/completion handler) however this is generally a poorer approach and is much less elegant than the delegation method.
If you are concerned about applying the on event to a certain element on the page. Then I would recommend just binding the event to the document.
$(document).on('click', '#id-of-a', function(){
});
Read this blog post for more information concerning this.
I found a solution. This is possible with using .detach()! tested.
When I'm writing some JavaScript I have a set of interface buttons that have their events assigned when the page is loaded. My problem is anything created dynamically wont receive these events.
For example, I'm making a URL checker, whose job is to make sure that any link that goes to another domain brings up an exit interface letting the user know they are leaving. Any links created after the page is loaded, post ajax (no pun intended) or whatever wont have that event naturally as those that existed when the page loaded.
In practice, what's the best way to ensure any newly created items get these sorts of global events?
I like to use jQuery, but this is really a conceptual question.
Should I create a function to re-apply any global link effects, or is there a smarter way besides doing it piecemeal?
If using jQuery, you can use the .live() method.
Normally when binding an event handler, the event handler is bound to a specific set of elements. Elements added in the future do not receive the event handler unless it is re-bound.
jQuery's .live() method works around this by binding its own special event handler to the root of the DOM tree (relying on event bubbling). When you click on an element, if it has no event handler directly attached, the event bubbles up the DOM tree. jQuery's special event handler catches the event, looks at its target and executes any user-specified event handlers that were assigned to the target through .live().
Look into jQuery's live function. It will allow you to attach to events when control are created during load, and whenever new ones are created. There is a performance penalty, but it is not significant unless you are loading a lot of elements.
You can use the .live() jQuery method to add listeners to elements that are created after the page is finished loading. Using your example of the exit link (if I understand it correctly):
$(function(){
$('a.exitLink').live('click',function(event){ /* do stuff when a link of class exitLink is clicked */);
});
This will respond to the click event on any link of class exitLink, regardless of when it was created (before or after onload fires).
Hope this helps :)
Yes put simply, where you might have had this before:
$('selector').click(function () {});
Replace it with:
$('selector').live('click', function() {});
When writing jQuery binding events, I typically use the bind() aliases (click(), submit(), etc).
But, the more I use dynamically generated content, the more I find its ambiguous as to when bind() won't work, and end up debugging for a half hour until I try live() and it works.
Within the parameters of ID-selectors (like '#foo', not .classes or elements ('input')):
Are there any drawbacks to just always using live() instead of bind() for these types of bindings, besides the lack of convenient aliases, since there can only be one DOM element tied to a particular ID?
===========
EDIT: I'm not asking what the difference between bind() and live() are; that's been covered. I'm asking what are the drawbacks of just using live() by default, since the temptation is to do so in instances where you can't mistakenly overselect (ie, when you're using a #uniqueDomElement), and avoid thinking about when bind() is not appropriate.
The main drawback to .live() is weight (this applies when using a large number of .live() handlers), since it attaches an event handler to document and events by default bubble up there (the entire basis of how it works) that means when the event reaches document a few things have to be checked:
Do I have any .live() events for this event type?
If I do, does the element the event came from match any selectors for those .live() handlers?
The first is pretty cheap, the second is not. Let's take the most common example, the click event. A click event bubbles, so far so good. Let's say we have one or more .live() event handlers for click registered on document...now we have to loop through all of those handlers and compare their selectors to the element the event came from, the more handlers you have, the more expensive this gets, and happens with every click, that's by far the biggest performance penalty for .live().
There are also other concerns, such as attaching/removing the handlers, but that's management of your handlers...the above performance concerns that apply when you have a large number of handlers are the main issue when comparing it to a direct .bind() call.
The problem you have with bind is that you must make the call to bind after the elements appear on the page.. In general people call bind on document ready so that they can attach behavior to elements on the page. If an element is added to the page via javascript after that you will need to then apply the same bind call for the new elements added, which is often cumbersome to do, and thus is why you can use .live instead.
.live uses event delegation which means that instead of having a function handler bound to specific elements on the page, jquery manages all the different live calls such that when you make some kind of action which a live handler exists for, it will check if the element you performed that action on matches the given selector (I believe this is how it works). My guess would be it it adds the event to the document body (for clicks/mouse actions)..
I'm not sure of the specifics but I know that ocassionally you can get some weird behavior with live if you use it for everything.. Usually its best to use if you have tons of elements which you will apply some behavior to or if you will be adding those elements dynamically via javascript.
Read the docs for more info: http://api.jquery.com/live/
It's a balancing act. Live() binds the events to the document and searches for the fired event target. The advantage to live (i.e. event delegation, in general) is that you are binding just one event handler for an infinite number of arguments. Bind() attaches the event handler directly to the element itself, so if you have 1,000 rows in a table, and you run $('tr').bind(...), you will be binding a 1,000 event handlers. If you did $('tr').live(...) then you would just be binding one event handler.
You can meet in the middle by using .delegate(), its different than live because you specify the context of the event. Therefore, it won't always fire thus is more efficient. Using the table example, you'd use $('table').delegate('tr', 'click', function() { .... });. You gain the advantages of both bind and live w/ minimal drawbacks: you bind 1 event handler, its future proof (w/i the context of that table only), you don't transverse the entire dom looking for 'tr' elements.
Bind, live and delegate all have their place.
Also, on a side note, delegate is just another way to do $('tr', $('table')[0]).live(), but that looks ugly, hence delegate exists.
This jQuery 1.3.2 code adds an element to the page, registers a "click" event, then removes and reattaches the element:
var button = $('<button>Click me!</button>')
.click(function(){ alert("Hello") })
.appendTo('body');
$('body').html('');
button.appendTo('body');
The button appears on the page as expected, but clicking on it does nothing. I would like to know why the event handlers were removed from the object.
Note: I am aware of solutions such as jQuery.live() or clone(true) or using appendTo without a removal. What I'm looking for is an explanation, not a solution or workaround.
EDIT: I suppose this could be an arbitrary and counter-intuitive design decision of the DOM. An explanation like "Because that's the way section X of specification Y wants it to be" would be fine.
When you remove an element from the DOM using jQuery, all data (including event handlers) held by jQuery on that element will be destroyed. This is done to avoid memory-leaks.
This isn't a feature (or bug) of the DOM API. It's just jQuery.
If you want your registered events to stay on your element use .detach() instead of .remove(). Use it the same way you'd use .remove(), it will keep your events on your element.