I was working on a form design recently in which I wanted the corresponding labels to disappear whenever text was entered into an input field.
This was easy enough to accomplish via jQuery, but I quickly hit a snag. I had assigned an event listener to the “change” event, but it turns out that the change event only gets fired when a user actively focuses on a field, inputs text, and then blurs. If a script — such as Google AutoFill — updates a value in a field on its own, the change event is unaware of it.
I poked around on Google a bit, and as far as I can tell, there doesn’t really seem to be an easy answer for this. So to make it work, I decided to write a quick jQuery plugin to handle the job.
I realized fortunately that rather than reinvent the wheel, all I need to do was find a way to listen for changes to input fields and then fire the change event manually if they were altered outside of the usual focus/blur routine (i.e. by a script).
Here’s the plugin code I came up with:
(function($) { $.fn.listenForChange = function(options) { settings = $.extend({ interval: 200 // in microseconds }, options); var jquery_object = this; var current_focus = null; jquery_object.filter(":input").add(":input", jquery_object).focus( function() { current_focus = this; }).blur( function() { current_focus = null; }); setInterval(function() { // allow jquery_object.filter(":input").add(":input", jquery_object).each(function() { // set data cache on element to input value if not yet set if ($(this).data('change_listener') == undefined) { $(this).data('change_listener', $(this).val()); return; } // return if the value matches the cache if ($(this).data('change_listener') == $(this).val()) { return; } // ignore if element is in focus (since change event will fire on blur) if (this == current_focus) { return; } // if we make it here, manually fire the change event and set the new value $(this).trigger('change'); $(this).data('change_listener', $(this).val()); }); }, settings.interval); return this; }; })(jQuery);
The plugin makes use of the trigger()
and data()
functions. In a nutshell, we loop over the input element or set of children input elements, storing their initial value in the data cache provided by the data()
function. We then check to see if the stored value matches the value of the input during the current iteration. If so, we do nothing, if not, we manually fire the change event via trigger()
.
There’s also a bit of logic in there to ignore the element that has focus. We don’t need to worry about this element, since if the value is changed while the user has focus, the change event will be fired as normal when the element is blurred.
That’s all there is to it. To use the plugin, you simply call listenForChange()
on the form or input you want to listen on, e.g.:
$("form").listenForChange();
You can then assign whatever functions you want triggered to the change event as normal, and they’ll be fired regardless of whether the user types them or they are updated via a script.
I’ve tested this on Firefox with Google AutoFill and Safari’s built-in AutoFill, and it seems to work on both. I haven’t tested it on fields injected after page load, but presumably it would work for these as well.