Detecting DOM changes

Don’t overthink it.

The Situation

While using a third-party plugin to upload multiple files in a form, I noticed that the plugin wasn’t behaving as expected. I bypassed the failing plugin option and wrote my own script to add certain attributes to a file picker form input. This worked for the static file picker on the page, but the attributes weren’t being added to any new file pickers added by the plugin. I needed a way to tell when the plugin added a new file picker so I could apply the desired attributes to it. Since there’s no onFileAdd event or equivalent, I decided to make one.

Limbo!

Back in 2000, a way to listen for changes to DOM elements was introduced in the Mutation Events API. Due to performance issues, it’s been deprecated and is scheduled to be replaced by DOM Mutation Observers in the upcoming DOM4 spec. Since most modern browsers have pulled the old functionality, and not all modern browsers have implemented the new functionality, we’re left in an awkward gray area. What do we do?

Workarounds (hacks…)

I suppose you could set up a debouncer to check every x seconds to see if any new file pickers have been added to the page, but that doesn’t sound performant at all.

The other option, that David Walsh so kindly laid out, is to add a CSS animation, which will automatically fire whenever a new file picker is added to the DOM. Add in a little bit of JavaScript to cleverly detect when the CSS animation completes, and you have your workaround. Brilliant.

First, we lay out the relevant CSS:

Then we can add in the appropriate JavaScript:

Using this method, I was able to apply new attributes to the last file picker added to the form. After the quick animation completed, of course.

In the example CodePen below, I show how a message is added to the document every time a new file picker is added.

See the Pen Detecting DOM Changes by Craig Freeman (@cfree) on CodePen.4550

While this method works and leverages the technology available today, we’re exploiting it. Who’s to say that these “features” will be around in a year from now? Specs change all the time, so this isn’t the best long-term solution. Here’s hoping DOM4 gets implemented soon.

Update

I had approached the problem from the angle of listening for DOM manipulation after another file input was dynamically inserted. As Alex points out in the comments below, this example is a perfect application for jQuery’s .on() method. Rather than wait for the plugin to add a new file picker, Alex suggested I try a different approach: listen for a user interaction before they select a file (which would also be before the plugin adds another picker) using $('.photos-container').on('click', 'input[type="file"]', ...);. Then I can test if the attributes exist before the users picks a file, adding them if they don’t. This way I still get the same functionality and don’t need to bog down my styles and scripts. Much more efficient!

It’s great to work for/alongside people who have been doing this longer than I have. The drawback is that I rarely have minor issues to overthink on the nights I can’t sleep! facepalm

References