I have a bunch of jQuery functions that use the .on event because I want to prevent reapplying the event to the same element.
However some people created plugins (e.g. Owl Carousel) and I don't know how to prevent this event from reapplying.
Currently I am using the plugin as following:
HTML:
<div class="init-owl"></div>
JS:
$('.init-owl').owlCarrousel();
$('.init-owl').removeClass('init-owl');
Whenever a second element gets loaded in the page using e.g. AJAX, I want to only apply the event to the newly added element.
Question: What I dont understand is how the event stays stuck to the DOM?
To better grip what is happening, I was wondering how an event in general gets connected to the DOM?
Is there a better way to prevent events applying to the same DOM elements?
If I wish to write my own plugins, I would need to know how javascript works, right?
Question: What I dont understand is how the event stays stuck to the DOM?
Once an event is bound to an object, it gets removed when the object gets garbaged collected. So if a DOM element is really gone and there are no references to it, then the event will get swept up as well.
To better grip what is happening, I was wondering how an event in general gets connected to the DOM?
I'm not sure how far you want to dive into this. Maybe it would help if you stop thinking about the DOM and events and look more at just regular events bound to objects. Basically an object does something, or something is done to it and some underlying code (in the browser's code in this case) triggers an event on that object. The implementations between browsers may differ, but basically you will have a key or string (the event name) that maps to a collection of functions. When you add an event listener, you add another function to this collection. Then when something triggers that event, it iterates through the functions and executes them. That's a real basic explanation, but I hope it makes things a little more clear.
Is there a better way to prevent events applying to the same DOM elements?
Make sure you don't add the events again by writing better code. I don't believe you can dive down into an element and look to see if it has events bound to it. You can however change your jQuery selector to only target newly added elements. If you have to, mark the elements that you have added events to with a class or something. Then you could target your elements by doing $('.init-owl:not(.already-bound)'). There is a better solution to your problem, I can assure you, but we might need more context and code to see a better way to help you.
EDIT:
You can look into jQuery's off() function to remove events. That may help you too.
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 .
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.
I am new in AJAX. I have searched a lot on Internet but only got basic AJAX steps. Now I am writing codes using AJAX but a common problem I am facing continuously.
When I place return text in the particular id of HTML page, Javascript effects do not work. CSS works fine but Javascript effects like table sorting, jQuery effects or any other effect does not work. I know I am missing some concept here. But didn't get any effective answer.
Please suggest me what should I do? And what is the concept behind this...
The new HTML you're adding to the DOM (page) didn't exist when your jquery ran the first time and bound events to elements on the page. You're probably using $("something").click(...) or .bind("click", ...). Instead of these use the delegate function from jquery. Delegate is generally more flexible and faster than live. For instance you can not stopPropagation in a 'live' binding.
Jquery Delegate
Why Delegate is better than Live
Here is another SO answer that explains the benefits of delegate
What's most likely happening is that your events are getting unbound because you update the DOM with new elements. The easiest solution is to use the live method to bind to events : http://api.jquery.com/live/
Or you can simply rebind the events to the elements after insertion to the DOM just as easily.
EDIT
As user kasdega points out, another alternative is to use delegate : http://api.jquery.com/delegate/ Delegate works by using the bound root elements as the context to rebind events to DOM elements that may appear in the future.
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.