0

Via a click event, I injected an element with a custom attribute
<div class="added" myValue="hello"></div> to the DOM.

I wrote a generic function:

$('.added').each(function(){
    console.log( $(this).attr('myValue') );
});

Doesn't work. I thought $.each() can handle dynamic elements?

UPDATE to the question:

I realize using .each() is the wrong approach. But what to do if I don't want to attach an event handler to the element. I just want to automatically do stuff to any elements of a certain class name, regardless of when they've been added to the DOM. Seems like a common use case.

tim
  • 3,823
  • 5
  • 34
  • 39

4 Answers4

4
  • No, each doesn't handle dynamic added elements, it only apply to the element that existed in the DOM when the jQuery object created(or modified).
  • .each function on id selector doesn't make any sense as id should be unique in the DOM. I suggest reading this: jQuery id selector works only for the first element

You must call each after you inject the element, or use delegate event, like on with selector.

Community
  • 1
  • 1
gdoron
  • 147,333
  • 58
  • 291
  • 367
  • hm. but I don't want to attach an event handler to the element. I just want to automatically do stuff to any elements of a certain class name, regardless of when they've been added to the DOM. – tim Jan 08 '13 at 22:11
  • @tim, I'm pretty sure I answered it with: _"You must call `each` after you inject the element,"_ – gdoron Jan 08 '13 at 22:13
  • I got that. I'm apparently using the wrong approach. Just searched google on how to select dynamic elements and all I find is stuff related to event binding. – tim Jan 08 '13 at 22:18
  • 1
    @tim. so did you got your answer? is there still something unclear? – gdoron Jan 08 '13 at 22:20
  • I don't understand why I'd have to use `delegate` or `on`, which are for events, since I'm not doing any event handling on the element. In the past, I'd simply use `.live('load'...` but since live is deprecated I'm no longer sure how to handle this. – tim Jan 11 '13 at 01:18
  • 1
    @tim, then you need to handle it manually, when you insert the element do what you want with it then. [`mutation events`](http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-mutationevents-h3) are deprecated, but will do the job, check the `DomNodeInserted` event, but you shouldn't use it as it has high performance penalty. – gdoron Jan 11 '13 at 05:05
3

$.each() will loop through the elements that are matching your selector at the moment you are calling this method. So if you call this method before adding the elements to the DOM dynamically you cannot possibly expect that this method will return you some elements that you might hypothetically add to the DOM at some future event.

So simply call the $.each() function after you have added the elements to the DOM.

Also there seems to be an inconsistency in your code. You are using an id selector $('#added') which can only return a single element. Yes, ids must be unique through the entire DOM. So calling .each() on a single element hardly makes any sense unless you have some broken HTML.

gdoron
  • 147,333
  • 58
  • 291
  • 367
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • yea. I excerpted this from my source code for clarity's sake, and should have used a class. – tim Jan 08 '13 at 22:09
  • Actually jQuery could have give you the new created elements as jQuery saves internally the selector you used to create the jQuery object. but still it doesn't do so, and for good reasons. – gdoron Jan 08 '13 at 22:12
1

When your click event happens, do your "something" there.

$("#someelemt").click(function(){
    var el = $("<div class='added' myValue='hello'></div>").appendTo("#someotherelement");
    console.log(el.attr("myValue")); // <--- something
});

ID's must be unique, so i changed added to a class.

If you want to separate the two, have your click event trigger an event, then use event delegation to listen for it.

$("#someelemt").click(function(){
    var el = $("<div class='added' myValue='hello'></div>").appendTo("#someotherelement");
    el.trigger("added");
});
$(document).on("added","div",function(){
    console.log(this.getAttribute("myValue")); // <--- something
});

$.each does not work with future elements, only the elements that exist when the code is executed.

Update for question Update
That simply isn't possible without writing inefficient code. It would require either using DOMMutationEvents which can be inefficient, are depreciated, and are not supported in all browsers, or you can use a setInterval which is also inefficient because it would be constantly running searching the dom for new elements.

Kevin B
  • 94,570
  • 16
  • 163
  • 180
  • it took me a while to understand your code. Are you saying `el.trigger('added')` is a custom event? And I have to explicitly listen to this event being fired using `document.on('added'...`? – tim Jan 11 '13 at 01:23
  • 1
    exactly, it's a custom event that you would then have to listen for. On it's own, it's pointless, but it can be used to add some separation between components – Kevin B Jan 11 '13 at 01:24
0

You can't use the same id attribute on multiple elements. You need different IDs each time. The ID selector # will only select the first of all of those elements, which is why it doesn't appear to be looping.

Although you really should change the ids of the other elements, this will actually still work:

$("[id=added]").each(...
Kevin B
  • 94,570
  • 16
  • 163
  • 180
Explosion Pills
  • 188,624
  • 52
  • 326
  • 405