Galactic Ranger
Galactic Ranger

Reputation: 882

Binding to dynamic elements

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);
});

Upvotes: 0

Views: 54

Answers (2)

Clayton Gulick
Clayton Gulick

Reputation: 10345

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.

Upvotes: 1

Joel
Joel

Reputation: 2257

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/

Upvotes: 0

Related Questions