Tuesday, March 19, 2024

Working with Inline Event Handlers

Inline event handling, it’s very mention brings shivers up developers’ backs! We’ve all heard the reasons that you should NEVER – and I mean NEVER – use them. I won’t reiterate them yet again here, but I’d like to point out that someone (likely Charles Dickens) also once said to “never say never!” Where ever there are perfectly good reasons not to do something, there are times when doing that very thing is exactly what’s called for! Now, I’m not here to tell you to start using inline event handlers in your Web pages, but I will venture to say that is that there is a distinct possibility that you will have to deal with them at some point. When that time comes, you should be aware of inline event handlers’ numerous caveats. In today’s article, we’ll learn how to add, modify, and remove inline event handlers using jQuery-assisted JavaScript.

Proof of Inline Event Handlers in the Real World

I had heard that Google’s main page contains many inline event handlers. I was skeptical at first, but one look at the source code confirmed it.

Google chose to use inline event handlers because they save server calls. They also place their JavaScript block at the bottom of their HTML code so that there is no external script loading. It’s all part of their strategy to improve performance at any cost, much like exotic sports car manufacturers who remove air conditioners and radios to make their vehicles faster.

Inline Event Handlers in Action

Inline events are bound to an element by their attribute name, which starts with the “on” prefix. Not all event types may be bound to all elements. For instance, onchange is usually associated with text input fields. Here is a list of some common HTML events:

  • onchange: An HTML element has been changed
  • onclick: The user clicks an HTML element
  • onmouseover: The user hovers the mouse over an HTML element
  • onmouseout: The user moves the mouse away from an HTML element
  • onkeydown: The user pushes a keyboard key down
  • onload: The browser has finished loading the page

The following elements feature a number of inline event handlers. Notice that the attribute value may contain a JS code string or function name. The link elements also use the ancient “javascript:” href value prefix. It harks way back to the early days of the Web when <A> tags did not support the onclick event. That was the only way to execute javascript from a link click.

  <a id="a link" href="javascript: doSomething(this);">click me</a><br>
	<a id="a link" href="javascript: function() { return false; };" onclick="console.log(this.id);">click me</a><br>
  <input id="a button" type="button" onmousedown="mouseDown();" onmouseup="mouseUp();" onclick="doSomething(this);" value="Click Me" />

The New Event Registration Model

As the unobtrusive JS movement gained traction in the mid to late nineties, inline event handling fell out of favour and was replaced by the element.addEventListener() and the IE-specific element.attachEvent() methods. The new registration model offered two huge advantages: first, they allowed you to bind event handlers in the JavaScript file, thus separating behavior from the content. Second, they permitted the queuing of multiple handlers, unlike the old model that clobbered any pre-existing handler.

jQuery made it even easier to attach event handlers to an element using the bind() or on() function:

$(document).ready( function() {
  //the id attribute selector works with multi-word IDs
  //$('#a button') does not
  $("[id='a button']").on( "click", function() {
    console.log( 'You clicked ' + this.id + '.' );
  });
});

A Clash of Styles

It’s just as easy to remove an event handler from an element using the jQuery off() function. The only trouble is, it only affects handlers that were attached using the new registration model; inline handlers remain intact. You need to approach those from a different angle, by setting the onxxx attribute to and empty string, or better still, by removing the attribute entirely using the jQuery removeAttr() function.

function removeInlineHandler(elt, eventType) {
  var $elt = $("[id='" + elt + "']");
  $elt.removeAttr(eventType);
  //this also works
  //$elt.attr(eventType, '');
}

Listing Registered Event Handlers

Prior to jQuery version 1.8, the data() function returned data associated with a specified element. Now, the internal equivalent _data() must be employed. It’s basically the same; it accepts the raw element and the datatype key.

$("[id='a button']").on( "click", function() {
  console.log( $._data(this, "events") );
});

To find inline event handlers, we must iterate through each attribute in search of those whose name begins with “on”. The grep() function is ideally suited to this purpose. It requires the attributes nodemap and a function that will test each attribute name for the “on” prefix. This particular function also checks for a value so that empty strings are not counted and thus considered to be unbound.

function getInlineEventHandlers($elt) {
  return $.grep($elt.get(0).attributes, function(attrib) {
    return /^on/i.test(attrib.name) && attrib.value.length; 
  });
}

Removing All Event Handlers from an Element

As mentioned earlier, the off() function may be used to remove event handlers bound using the new registration model. Calling it without any arguments causes all handlers to be removed in one fell swoop.

Iterating over an element’s attributes for the purpose of removing event handlers is not as simple as you might think. Using the each() iterator is error-prone because it doesn’t know when the source array has shrunk, leading to null pointers. It’s far better to use a traditional while loop.

function removeAllHandlers(eltID) {
  //wrap with jQuery
  var $elt = $("[id='" + eltID + "']");
  
	//turn off all registered event handlers
	$elt.off();

	//filter out event handlers from attributes
	var i = 0, attrib, attribName;
	while (attrib = $elt.get(0).attributes[i++]) {
		attribName = attrib.name;
		if (/^on/i.test(attribName)) { 
		  $elt.removeAttr(attribName); 
		}
	}
}

Conclusion

Despite numerous sound reasons for not using inline event handlers, those mavericks of the scripting world that they are, refuse to say die! At least now you’ll be better equipped for dealing with them.

Rob Gravelle
Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured