This was previously discussed here: How to do an action when an element is added to a page using Jquery?
The responder suggested triggering a custom event whenever a div was added to the page. However, I'm writing a Chrome extension and don't have access to the page source. What are my options here? I guess in theory I could just use setTimeout
to continually search for the element's presence and add my action if the element is there.
ETA 24 Apr 17 I wanted to simplify this a bit with some
async
/await
magic, as it makes it a lot more succinct:Using the same promisified-observable:
Your calling function can be as simple as:
If you wanted to add a timeout, you could use a simple
Promise.race
pattern as demonstrated here:Original
You can do this without libraries, but you'd have to use some ES6 stuff, so be cognizant of compatibility issues (i.e., if your audience is mostly Amish, luddite or, worse, IE8 users)
First, we'll use the MutationObserver API to construct an observer object. We'll wrap this object in a promise, and
resolve()
when the callback is fired (h/t davidwalshblog)david walsh blog article on mutations:Then, we'll create a
generator function
. If you haven't used these yet, then you're missing out--but a brief synopsis is: it runs like a sync function, and when it finds ayield <Promise>
expression, it waits in a non-blocking fashion for the promise to be fulfilled (Generators do more than this, but this is what we're interested in here).A tricky part about generators is they don't 'return' like a normal function. So, we'll use a helper function to be able to use the generator like a regular function. (again, h/t to dwb)
Then, at any point before the expected DOM mutation might happen, simply run
runGenerator(getMutation)
.Now you can integrate DOM mutations into a synchronous-style control flow. How bout that.
A pure javascript solution (without
jQuery
):You can use
livequery
plugin for jQuery. You can provide a selector expression such as:Every time a button of a
removeItemButton
class is added a message appears in a status bar.In terms of efficiency you might want avoid this, but in any case you could leverage the plugin instead of creating your own event handlers.
Revisited answer
The answer above was only meant to detect that an item has been added to the DOM through the plugin.
However, most likely, a
jQuery.on()
approach would be more appropriate, for example:If you have dynamic content that should respond to clicks for example, it's best to bind events to a parent container using
jQuery.on
.Check out this plugin that does exacly that - jquery.initialize
It works exacly like .each function, the difference is it takes selector you've entered and watch for new items added in future matching this selector and initialize them
Initialize looks like this
But now if new element matching
.some-element
selector will appear on page, it will be instanty initialized.The way new item is added is not important, you dont need to care about any callbacks etc.
So if you'd add new element like:
it will be instantly initialized.
Plugin is based on
MutationObserver
The actual answer is "use mutation observers" (as outlined in this question: Determining if a HTML element has been added to the DOM dynamically), however support (specifically on IE) is limited (http://caniuse.com/mutationobserver).
So the actual ACTUAL answer is "Use mutation observers.... eventually. But go with Jose Faeti's answer for now" :)
Since DOM Mutation Events are now deprecated (see note at the bottom) with the latest specifications, and you have no control over the inserted elements because they are added by someone else's code, your only option is to continuously check for them.
Once this function is called, it will run every xxx milliseconds. I chose 100, which is 1/10 (one tenth) of a second. Unless you need real time elements catch, it should be enough.
Edit
As commented by Ben Davis, DOM Level 4 specification introduces Mutation observers (also on Mozilla docs), which replace the deprecated mutation events.