Tracking text input changes in real time

Nov 25, 2009

A very useful event fired for <select> form elements is the change event. This event fires each time you select a new value, even if the element remains focused. In essence, it fires after each time a user fiddles with it.

The change event also fires on text field form elements, however it only does so when the element loses focus and the value has changed since it was focused. This means that it doesn't fire for each time the user interacts with it, only when the user is finally finished with it. For real-time validation functions you want to attach to your text fields, the change event just isn't going to work. You need something that fires for every user interaction, every value change, even if the element retains focus after the change.

Initially the solution might appear to be using the keypress event to trigger validation. Seems simple enough, right? Every time the user presses a key, an event is fired which we can use to trigger a validation function. However, this doesn't account for input methods which don't use the keyboard, such as using the context menu (via right mouse click) to cut, paste or delete selected characters from the text field. These input methods, which change the value of the text field, don't trigger the keypress event at all. So, what to do?

The input and propertychange Events

The answer lies in a new event introduced in the Web Forms 2.0 specification, and later in the HTML5 specification: the input event. The input event fires on form elements whenever the user changes their contents, no matter which input method they used to do it, keyboard or mouse. It differs semantically from the change event in that the input event fires for every edit, while the change event signifies a "commitment" of changes, as in the user is done editing.

Of course, it can't be as simple as a single new event that works everywhere. For one thing, while current versions of Opera, Firefox, Chrome and Safari all support the input event, Internet Explorer (up to version 8) still lags behind in the implementation. Fortunately, IE does support a proprietary event called propertychange (IE5 and later) which mimics the input event. See the support table below:

EventTriggerOperaFirefoxIE8ChromeSafari
* Listener must be set using addEventListener()
inputKeypressYesYes*NoYesYes
CutNoYes*NoYesYes
PasteYesYes*NoYesYes
DeleteYesYes*NoYesYes
propertychangeKeypressNoNoYesNoNo
CutNoNoYesNoNo
PasteNoNoYesNoNo
DeleteNoNoYesNoNo
cutCutNoYesYesYesYes
pastePasteNoYesYesYesYes

Update (2011): Current versions of Opera fire the input event on cut.

It seems almost too good to be true that the lack of support for the input event in IE is perfectly covered by one of its proprietary events; just add both events to an element and you're set. Taking a closer look at the table, however, we find that Opera is being a party-pooper and fails to fire the input event when a "Cut" command is issued by the user, whether through Ctrl+X or the context menu. You also can't even use the cut event since Opera neither supports that event, nor paste nor copy. So we are just out of luck on this loophole.

The attachTextListener Function

Aside from that issue, which hopefully the Opera team will fix post-haste, we can now attach a function to an input element which will trigger on any user change, from any input method, in real time.

function attachTextListener(input, func) {
  if (window.addEventListener) {
    input.addEventListener('input', func, false);
  } else
    input.attachEvent('onpropertychange', function() {
      func.call(input);
    });
}

var myInput = document.getElementById('myInput');
attachTextListener(myInput, function() {
  // Check and manipulate this.value here
  ...
});

Note the two different methods used to attach the validation function: the addEventListener() method for Opera, Firefox, Chrome and Safari, while the attachEvent() method is used for Internet Explorer. Because events are executed in the global scope in IE, we call the function in a special way using .call() so the listener function can use the this keyword in both cases.

An interesting issue, which doesn't affect the code above, is a long-standing bug in Firefox requires that we attach the listener using addEventListener() only; using the old style .oninput fails in Firefox.

And there you have it. Tracking user changes to text fields in real time, without using clunky keypress and change event listener combos, or the dreaded setInterval() (the horror... the horror!). Works as expected in all the browsers mentioned, except for Opera in which a "Cut" command won't trigger the event.

Enjoy! :)


Comments closed

Recent posts

  1. Customize Clipboard Content on Copy: Caveats Dec 2023
  2. Orcinus Site Search now available on Github Apr 2023
  3. Looking for Orca Search 3.0 Beta Testers! Apr 2023
  4. Simple Wheel / Tire Size Calculator Feb 2023
  5. Dr. Presto - Now with MUSIC! Jan 2023
  6. Archive