Who started it?

I spent some time this evening thinking about ideas for progressing form validation code.

Specifically, I was trying to solve the conundrum: When the submit event for a form is triggered, how can you tell which user interface element triggered the event?

This problem typically arises when you have multiple submit buttons on a form, when any submit button is activated, the submit event is triggered, but the form element is passed as a property of the event object, not the element (in this case a button) that originally triggered the event.

To complicate matters further, pressing enter while focussed on any input element will also trigger the submit event in many user agents.

Finding a complete robust solution became a bit of an emotional roller-coaster, let me explain…

  1. My initial investigation revealed that jQuery was returning a useful object eventObj.originalEvent.explicitOriginalTarget. 🙂

    For example:

    $('form').submit(eventObj) {
    	var iStartedIt = eventObj.originalEvent.explicitOriginalTarget;
    };

    Unfortunately, it turned out that explicitOriginalTarget is a Mozilla-specific property, with no cross-browser alternative. 🙁

  2. My next thought was that the currently focussed element would have to be the element that triggered the submit event! 🙂

    Unfortunately, jQuery doesn’t have a :focus selector. 🙁

  3. I found a proposed solution for extending jQuery with a :focus selector. 🙂

    Unfortunately, it relies on document.activeElement, which is a property only supported in IE, and modern browsers that have implemented parts of the HTML5 draft specification. 🙁

  4. Luckily, a good fellow proposed a way to support document.activeElement in older browsers that don’t implement it themselves. 🙂

    And… even better, this seemed to work (well, mostly – see below).

All together now

So put all this together and we get:

// Add document.activeElement support to browsers that don't support it.
if (
	typeof document.activeElement == 'undefined' &&
	document.addEventListener
) {
	document.addEventListener("focus", function(e){
		if (e && e.target) {
			document.activeElement = e.target == document
				? null : e.target;
		}
	}, true);
}

// Extend jQuery to support :focus selector
jQuery.extend(jQuery.expr[':'], {'focus': function(e) {
	return (document.activeElement)
		? e == document.activeElement : false ;
}});

// Now on submit, we can find the element that triggered this event
$('form').submit(function(eventObj) {
	// if a submit button triggered the submit event, find it
	if ((focussedSubmit = $(this).find(':submit:focus')).size() > 0) {
		var iStartedIt = focussedSubmit;
	} else {
		// otherwise find the first submit button
		var iStartedIt = form.find(':submit').eq(0);
	}
	
	// The iStartedIt variable now contains a reference to the element 
	// that triggered the submit event!
};

Tested and working in Firefox 2, Firefox 3, Opera 9.5 but not working correctly in Chrome. IE versions were not tested at this time, but in theory IE6+ should be fine.

Posted in

Leave a reply