Adding a Javascript Event Listener
Page: prev. | 1 | next
Cascading Style Sheets (CSS) did much to manage the maintenance of styling of HTML markup, and the use of quickly became universal.
An elements style could be defined and all those elements present on a page or pages if an external style sheet is used would be styled accordingly.
Style was separated from markup, so gone were the days of having to trawl through pages to change font tags and the like when a style needed to be updated making maintenance easier: update the style sheet and all elements present in all pages are styled accordingly.
A hold-over from those pre-CSS days is noted in the use of Javascript where an elements events are often used to trigger Javscript code.
Pages can be full of onclick and onmouseover events and as well as swelling a page a change in a script's actions can result in one of those long trawls through a whole site's pages to update.
Events are often the beating heart of Javascript; in nearly all cases it is an elements event such as it being clicked on or rolled over that triggers script.
Used like this Javascript is often declared "obtrusive" as it does not follow the CSS creed of separating style from content. Javascript used in this manner can however be made unobtrusive with an "event listener".
Event Listening
An element's event action can be set entirely through JavaScript without need of on[action] properties included with the element's markup, thus adhering to the CSS creed of separating style from content.
Let's try a simply example in the way of a division tag which will just pop up a dialog when clicked.
This is what we want to get away from:
- <div id="div1" onclick="giveMessage();return false;">Click me for a message!</div>.
The simplest method to apply an event listener for events from within a JavaScript block is to use the Document Object Model (DOM) level 0 specification.
- <div id="div1">Click me for a message!</div>.
- <script type="application/javascript">
- function giveMessage() {
- //Function to show message when onclick event occurs.
- alert('You got me!');
- }
- function initialiseListener() {
- //Sets function to trigger when the element's onclick event occurs.
- var el = document.getElementById('div1');
- el.onclick = function() {
- giveMessage();
- return false; //Cancel default event behaviour.
- }
- }
- window.onload = function() {
- //Set event listener when page has loaded.
- initialiseListener();
- }
- </script>
window.onload
(line 23) is the event handler for the load event of the window, triggering when the page has completed loading. It executes an anonymous function which
calls the initialiseListener
function (line 25), which stores a reference to the div
element by its ID
(line 14) and then adds (or attaches) a listener which will listen for
when an onclick
occurs to the element by attaching an anonymous function (line 16) to the element's onclick event with the syntax function(){FunctionName();return false}
. This will, when the event occurs, execute giveMessage
(line 17), popping up a
dialog and then cancel the element's default behaviour for that event by returning false
(line 18). (Not that a div element actually has a default behaviour for an onclick event, but in case it did).
Simple! But not very useful.
Let's, try a more complex (and useful) example, and also step-up our game a little by using the more advanced W3C DOM level 2 specification (or Microsoft's proprietary specification). Let's trigger a Javascript function to append a query string to a URL (which Javascript can read) when the anchor element's onclick event occurs.
For this example, we will pass an argument (a URL) along with the event and overide the element's default behaviour, which is to load the URL specified by the anchor element's HREF property and instead load the new page with the query string attached via the specified function.
- <a id="link1" href="http://www.artofgladstonetibbs.com/">Show me the boobies!</a>.
- <script type="application/javascript">
- //Query string to append to url.
- var qstring = '?y=2012';
- function preventDefaultAction(evt) {
- //Prevents element's default action.
- if (evt) {
- if (typeof evt.preventDefault!= 'undefined') {
- evt.preventDefault(); // W3C
- } else {
- evt.returnValue = false; // IE
- }
- }
- /* For safety's sake return false just in case called by an inline onclick or an older DOM Level 0 event listner. */
- return false;
- }
- function loadUrl(evt,url) {
- //Function to load url with query string attached.
- document.location.href = url + qstring;
- return preventDefaultAction(evt);
- }
- function initialiseListener() {
- //Sets function to trigger when the element's onclick event occurs.
- var el = document.getElementById('link1');
- var listenerFunction;
- //IE < 9 does not support addEventListener, but does support attachEvent.
- if (el.addEventListener) {
- /* Use addEventListener for w3c DOM.
- Syntax: target.addEventListener(event type, function, useCapture); */
- el.addEventListener('click', function(evt){loadUrl(evt,this)}, false);
- } else if (el.attachEvent) {
- /* Use attachEvent for IE < 9.
- Syntax: target.attachEvent(event type, function); */
- el.attachEvent('onclick', function(evt){loadUrl(evt,document.getElementById('link1').href)});
- }
- }
- window.onload = function() {
- //Trigger Event listener when page has loaded.
- initialiseListener();
- }
- </script>
The listening event triggers in the same manner as in the first example, but this time the syntax of the function specified for the listener to call is a little more complex.
It needs to be passed as an anonymous function with the syntax function(evt){FunctionName(parameters)}
. This time return false
is not used to cancel the event's
default behaviour: it will be canceled in the function called.
The function called this time is loadUrl
. However, depending on whether the browser uses the DOM 2 specification (as all recent browsers do) or Microsoft's proprietary
specification used with versions of Internet Explorer 9 or less, we must use either addEventListener
(line 38) or attachEvent
(line 42).
The DOM 2 specification's syntax is target.addEventListener(event type, function, useCapture);
. Microsoft's proprietary specification's is
target.attachEvent(event type, function);
. As you can see, the DOM 2 specification has an extra parameter, useCapture
. For the moment, let's just set that to
false
and I'll come back to that.
The first parameter is the
event (evt), the second argument is a URL drawn from the element's HREF property. The DOM 2 specification can make use of Javascript's this
keyword, which references the
current object, in this case the anchor element, which will return the anchor's HREF property. The old IE method has to get the URL with getElementById
.
The first line of the loadUrl
function (line 24) appends the query string to the URL string and loads that URL, the second (line 25) calls another function,
preventDefaultAction
to cancel the event's default behaviour, which would be to load the URL specified by the anchor's HREF property.
I chose an anchor element as an example as it is a common target for Javascript events and could show how the default behaviour of the element's event is overidden, equivalent to adding return false in the DOM level 0 example.
You would be right in concluding that the DOM level 2 code is hugely more complex than the DOM level 0 example, but the DOM level 2 specification does provide two advantages in return for it's complexity.
The first is, at present though, not all that useful at all due to cross-browser incompatabilities, so much so that even hardcore Javascript illuminati with a bias for a particular browser seem to wince when considering it.
It's that useCapture
parameter which allows an element
with a listener to intercept (or capture) the same event occuring on any child, or nested elements and determine whether to pass it on or not or do something else. Huge potential, but
each different browser seems to handle it differently and that's a browser-specific quagmire we really shouldn't be in after all this time.
The second advantage though is much more useable, and that is that both addEventListener and attachEvent allow event listeners that have been attached to be un-attached. And that's something I'll come back to in a future blog entry.
Although more complex than the venerable but simple onclick property, using an event listener pays dividends when it comes to maintenance. The script could be placed in an external .js file and any changes that need to be made to the code only need be made to that single file even if the named element is contained in dozens of pages, making the Javascript used much, much less obtrusive.
That's it, I'm done. Hope you can find a use for it.
Page: prev. | 1 | next