5

Let me illustrate my question: I have an external JavaScript library that creates certain HTML elements for me dynamically based on user input and interaction, and I'm looking to write a script that would automatically add a certain class to these dynamically created elements. Assume that I also am unable to edit the external JavaScript library I'm using.

Is this elegantly possible? If so, how? If not, could this be a side-effect of poor implementation design?

I've thought about somehow monitoring the DOM to see when it was updated, and adding the classes to these new elements then, but this seems cumbersome and possibly unnecessary.

Thanks in advance for any thoughts / solutions!

Edit:

As requested, here's a simplified example of what I'm trying to accomplish with a code sample:

// function in external library, assume it cannot be edited!
function addElement() {
    $('body').append($('<div class="newly_created_element"></div>'));
}

// my code, looking to add the class name to the newly-created elements
// from the external function above...
// pseudo-coded as I have no idea how to do this!
$(function(){
    when (new element added) {
        add class "my_own_class";
    }
});

I hope this makes sense!

Chris Kempen
  • 9,491
  • 5
  • 40
  • 52
  • Post a code sample/more detail of how this currently works? – Paddy Sep 24 '13 at 11:08
  • 2
    if the third party library is not providing any custom events then it is a tough one – Arun P Johny Sep 24 '13 at 11:10
  • 2
    A good API allows you to define a callback function, which for example is called for each element after its creation. – Sebastian vom Meer Sep 24 '13 at 11:10
  • you can have a loot at [mutation events](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Events/Mutation_events) but IE support is not there for IE < 9 – Arun P Johny Sep 24 '13 at 11:11
  • Maybe ths is working. $("element-root").bind(DOMSubtreeModified,"CustomHandler"); found here http://stackoverflow.com/questions/9488653/jquery-how-to-listen-for-dom-changes – Bernhard Sep 24 '13 at 11:11
  • Shaky IE support makes my stomach do the same, and as I commented in @Moeri's answer below I was hoping to have missed a jQuery function like `$.magicallyMonitorThis(do_something());` :') Thanks for the helpful suggestions and comments! – Chris Kempen Sep 24 '13 at 11:20

6 Answers6

12

You can do something like:

$("body").bind("DOMNodeInserted", function() {
   $(this).find('.newly_created_element').addClass('my_own_class');
});

See more on DOMNodeInserted here

MaVRoSCy
  • 17,747
  • 15
  • 82
  • 125
5

Hi I made a jsfiddle dealing with your issue. The click on the button simulates your external libary adding a element. Unrelated to the button click I'm listening on DOMNodeInserted. If there is something inserted in the dom a class is added. You could easily modify the script to only add a class to certain elements.

http://jsfiddle.net/kasperfish/AAd8f/

$(function() {
    $('#btn').click(function(){
        $('body').append('<div style="width:30px;height:30px;border:1px solid black"></div>');
    });


    $(document).on('DOMNodeInserted', function(e) {

        $(e.target).addClass('blue');
    });


});
kasper Taeymans
  • 6,950
  • 5
  • 32
  • 51
  • Thanks for providing a fiddle for this kasper, although I'm still a little hesitant to use mutation events when IE is uncertain of it's abilities...good suggestion! – Chris Kempen Sep 24 '13 at 11:38
  • 1
    there is a jquery plugin out there that might help you. have a look here: http://stackoverflow.com/questions/3900151/is-there-a-jquery-event-that-fires-when-a-new-node-is-inserted-into-the-dom however I don't know how the plugin works :-/ – kasper Taeymans Sep 24 '13 at 11:48
  • It seems that plugin is no longer available, but it also only seemed to trigger on jQuery events...not bad if it were still around :( – Chris Kempen Sep 24 '13 at 11:52
2

Surely there is a wrapper class or id that library uses that you can use too. Just add css styling to that wrapper. I never found a library where I couldn't hook onto it's wrapper class/id definition.

Failing that, you need act on changes made by that script. Possibly by adding a listener to a specific user interaction or, like you mentioned, a DOM update. Maybe you can add a listener or callback on the external script itself.

I could give a more accurate answer on that if I knew more about the specific external script.

Regarding your snippet: you can listen for DOM updates like this $(".newly_created_element").bind(DOMSubtreeModified, function() { this.addClass('class'); });

hvgeertruy
  • 198
  • 6
  • You're right, there is a wrapper, but to add to the annoyance I'm trying to add [Twitter's Bootstrap CSS classes](http://getbootstrap.com/css/#buttons) to the buttons that get added dynamically, and I didn't want to copy / paste that style information into the wrapper too. With regards to the external script, it's something I've written, but is used extensively within my organisation from a CDN and can't be modified. Trust me to want to push the limits...helpful suggestions though, thank you! – Chris Kempen Sep 24 '13 at 11:24
  • 1
    Outch, I understand your problem.. Tough one. My next guess would be user interaction. Is the code update always initiated by a user interaction? Or by a regular time interval? You might pick up on that and evaluate the classes (ex. $('trigger').on('click', function($('.newly_created_element').addClass('bootstrap classes')))}; – hvgeertruy Sep 24 '13 at 11:30
  • Always by user interaction, but it's difficult to say when the elements are actually added to the DOM, hence my currently thinning hair... ;) – Chris Kempen Sep 24 '13 at 11:32
  • 1
    A final try: Use less/sass mixins to extend your classes to bootstrap classes with Less/Sass. Ex (in less): .newly_created_element { .btn; .btn-large; }. Good luck – hvgeertruy Sep 24 '13 at 12:40
1

For the sake of thoroughness and bringing a clear solution to my question to light, herewith my conclusion. Thank you all for your thoughts and suggestions, I've learnt a lot and clearly got people thinking!

Initially I was hoping for a magical jQuery function that I'd perhaps overlooked, something along the lines of:

$("#parent-element").monitorDom(function(added_element){ ... });

...but there just isn't anything, which is probably a good thing because I suspect I've stumbled onto poor code design, and allowing for hooks and callbacks is a better way to go. I.e.: use the smaller, established and tested building blocks instead of trying to over-engineer something.

If you don't care about supporting Internet Explorer and it's quirks, you may definitely look at the deprecated mutation events, or their replacement the MutationObserver. Here is also a decently answered SO question with the use of mutators: Is there a JavaScript/jQuery DOM change listener?

In a nutshell, as of this post, there is no built-in jQuery function to monitor DOM changes, and in my case my problem can be resolved with better code design. Thank you all for all the answers, and let's keep pushing the limits!

Community
  • 1
  • 1
Chris Kempen
  • 9,491
  • 5
  • 40
  • 52
0

If I were you, I would use events. jQuery makes it easy. Here are the first three links from Google: http://www.sitepoint.com/jquery-custom-events/, https://stackoverflow.com/a/14840483/993216, http://api.jquery.com/trigger/.

In one module you load the data from server, perhaps process it and trigger the event. In another module you can listen to that event and do whatever you need. In my opinion this is the best approach. This is very agile way to build and app because you can add another modules.

Community
  • 1
  • 1
Ivan Demchenko
  • 457
  • 3
  • 13
  • Thank you for this Ivan, again helpful suggestions all round, but how would I trigger any of the events I created without editing the external script file? – Chris Kempen Sep 24 '13 at 11:29
  • 1
    Oh, I apologize. I was inattentive when I was reading your question. :( In your case for sure, DOM mutation events is the proper solution. http://updates.html5rocks.com/2012/02/Detect-DOM-changes-with-Mutation-Observers – Ivan Demchenko Sep 24 '13 at 11:35
-3

This works fo me, I keep on checking wether that class exists or not ,once it finds it ,the interval function stops

var interval=setInterval(function(){ 
    if($('._icon').children().hasClass('_share')){
      clearInterval(interval);
    }else $('._icon').children().addClass('_share');
}, 1000);
manish
  • 1