0

I'm trying to detect if an element with a specific tag name has been inserted into the document. I am aware of DOMSubtreeModified and MutationObserver and I know that they can detect changes in the elements, but if the document is big and many changes are applied to the document, these two methods can become quite heavy.

One of the ideas I had was to collect all elements using getElementsByTagName and then detect a change of HTMLCollection's length property but I didn't find any method that could watch this property and trigger an event.

Another idea I had was to set an interval, but the problem with this is that an item can be deleted and inserted in between the timer and this wouldn't be detected in the interval's function.

Is there any efficient way of detecting new element insertion in the whole document? Alternatively, how can I detect change of HTMLCollection's length property?

Thanks for any answer.

leopik
  • 2,323
  • 2
  • 17
  • 29
  • 1
    this will surely help for first part http://stackoverflow.com/questions/3219758/detect-changes-in-the-dom – Milind Anantwar May 04 '15 at 12:00
  • what about these: http://stackoverflow.com/q/4780822/20126 http://stackoverflow.com/q/7434685/20126 http://stackoverflow.com/q/10415400/20126 – Amr Elgarhy May 04 '15 at 12:02
  • "if the document is big and many changes are applied to the document, these two methods can become quite heavy." - how did you infer this? Did you run any tests? – bhavya_w May 04 '15 at 12:04
  • @bhavya_w No tests are needed - as a user of the website I could feel the difference in responsivnes. – leopik May 04 '15 at 12:06
  • Thanks for the links, but all of them are handling it by watching the whole document and I don't think this is an efficient way of doing it, considering that there may be lots of DOM changes and firing an event after every change doesn't sound right. Moreover, I do not have full control of the document, so creating my custom event that would be called only on insertion of specific tag will not work either. – leopik May 04 '15 at 12:15
  • The best solution in my opinion would be to watch changes of a HTMLCollection – leopik May 04 '15 at 12:17
  • If you want a specific tag, you can do this: `var num=document.getElementsByTagName("mytag").length;tId = setInterval(function() { var newNum = document.getElementsByTagName("mytag").length; if (newNum!=num) { console.log("Someone manipulated mytag "+(newNum-num)+" times"); num=newNum;}},200);` – mplungjan May 04 '15 at 12:42
  • @mplungjan Thanks, I have already thought about it, but the problem is - what if I remove `mytag` and then after it I add a new `mytag` and all this happens faster than 200ms? In this scenario, a new element would be inserted, but I would not notice any change. – leopik May 04 '15 at 13:58
  • How likely is this? And what is the issue about noticing? What are you actually trying to find out? You could also override some dom manipulation functions – mplungjan May 04 '15 at 14:09
  • I want to get all `select` elements, attach some events to them and whenever a new select is inserted into the website, I want the script to automatically detect it and attach the events ... I guess it's not very likely, but it might happen. – leopik May 04 '15 at 14:11
  • That is a simple delegation in jQuery. See updated answer – mplungjan May 04 '15 at 14:47

1 Answers1

2

Here is a thought:

var cnt=0;

var f = Element.prototype.appendChild;
Element.prototype.appendChild = function(){
   f.apply(this, arguments);
   console.log("added",++cnt) 
};

However you will need to see if it is the same element that is added and I have not figured out how to check the remove since that is parentNode.removeChild

If you want events on all selects in jQuery all you have to do is delegate

$(document).on("change","select",function() { 
  // all current and future selects will have this event
});
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • Very good idea! If watching HTMLCollection's length parameter isn't possible then this comes very close to what I need. – leopik May 04 '15 at 14:30
  • ... Also, I wouldn't mind adding a `data` parameter on the `select` where I could mark whether I have already attached the events to it so this way in the modified `appendChild` I would just check if the element being attached is `select` and whether it has a correct `data` parameter. – leopik May 04 '15 at 14:35
  • 1
    But you can. Add a data-attr to arguments[0] if its tagName.indexOf('select')===0 – mplungjan May 04 '15 at 14:43
  • Please see update for a better solution for your specific issue – mplungjan May 04 '15 at 14:46
  • 1
    Yes, that's what I meant, I was just thinking out loud. I think this is the solution to my problem then. Thanks again. – leopik May 04 '15 at 14:51