Instant onChange with IE checkboxes

Browser differences are a daily fact of life for webdevelopers. It is something you either learn to deal with, or it kills you before 40.

Some of these are just plain stupid, but some are simply different ways of interpreting the standard. A good example is the onChange event. This is a simple event, commonly attached to <input /> elements, that fires when the state or value of the element has changed.

For normal text fields, this event fires when the element loses focus. This is logical, since you don’t want it to fire after every keypress. However, for other types of field, the behaviour differs between browsers. Internet Explorer is consistent between types, and always waits till the element loses focus, regardless of the type attribute. Most other browsers however fire the event immediately if the states of the element are clearly defined. Radiobuttons and checkboxes for instance, are either on or off, so the event can fire as soon as the state changes, but IE still waits till the focus is moved to another object.

This leads to problems when the state of a checkbox or radiobutton has influence on other fields in the form. Take for example a situation where the state of a checkbox determines whether a submit button is enabled or not. In IE, the user has to click the checkbox, then click somewhere else in the form, and only then can he submit the form.

The most common workaround for this is to use the onClick event instead of the onChange event, but this will fire on every click, not just if the click actually changes the content.
I recently solved the problem much more elegantly: In addition to the normal onChange event, add an onClick event that removes focus from the element: onclick="this.blur()". When the user clicks the element, it is changed, and focus is immediately moved elsewhere. This means the onChange event is always called immediately, regardless of browser.

An even more advanced version would move the focus to the next element in the form: onclick="focusNext(this)", with the function defined as:

function focusNext(elem)
{
	var formElems = elem.form.elements.length;
	var thisIndex = $.inArray(elem, elem.form.elements);
	var nextIndex = Math.min(formElems-1, thisIndex+1);
	elem.form.elements[nextIndex].focus();
}

Note that this version requires JQuery. Some browsers support the Array.indexOf() method, in which case you could use: 

function focusNext(elem)
{
	var formElems = elem.form.elements.length;
	var thisIndex = elem.form.elements.indexOf(elem);
	var nextIndex = Math.min(formElems-1, thisIndex+1);
	elem.form.elements[nextIndex].focus();
}

However, this method is very sparsely supported, and while you can add it yourself via prototype, I find that JQuery is useful enough that I usually add it to my site anyway.

No Comments

Leave a Reply

Your email is never shared.Required fields are marked *