Oneupweb : Cross Browser Event Binding Without jQuery

This past weekend I was having a conversation on JavaScript with a developer friend of mine and we got on the topic of how jQuery has drastically altered the JavaScript landscape. Don’t get me wrong, jQuery is an excellent library. It makes cross browser events and effects a snap. The problem is it has become universally depended on for even trivial tasks. There seems to be a tendency to learn jQuery and not JavaScript.

People asking JavaScript questions on a site like Stack Overflow are inundated with responses to the effect of “why not just use jQuery.” Well yes… you could accomplish it that way, but it doesn’t help the asker of the question to understand anything new about JavaScript.

Do It The Right Way

If all you need to accomplish is a simple hide/show function at the click of a button, then why include the whole jQuery library? Do you really need all that code mucking up your window for such a simple task? Lets go over the basics of creating a nice lean cross browser event and css tool in JavaScript.

Binding Events

The trick to binding events that work in multiple browsers is basically understanding the Internet Explorer method and the standard method defined by the W3C.

element.addEventListener

This is the standard way to setup events in a document. A great introduction to this method can be found on the Mozilla Developer Network.

The syntax is as follows:
target.addEventListener(type, listener, useCapture /* Optional */);

document.getElementById('mybutton').addEventListener('click',function(e){
    //"this" refers to the event target ie the button that was clicked
    alert(this.value);
},false);

The function you pass in to addEventListener will receive the event object as its first argument. Within the function the this keyword refers to the element that was clicked. The false passed at the end keeps the element’s parents from getting to the event first (this is ok for most basic uses);

element.attachEvent

Internet Explorer is not historically known for working with standards. Internet Explorer, before version 9 (though 9 still supports it), relied on element.attachEvent for event binding.
The syntax for this is:
target.attachEvent(ontype, listener);
Just replace type with the event you would normally use in element.addEventListener. So click becomes onclick, change becomes onchange, etc…

document.getElementById('mybutton').attachEvent('onclick',function(){
    //attachEvent relies on a global event object to get the target
    var elem = event.srcElement;
    alert(elem.value);
},false);

A Cross Browser Function

You can’t just choose one or the other. Ideally you will have one way to bind an event and you should be confident that whether your document is being viewed in IE7+, Firefox, Chrome or whatever – the events should all work the same.

Our function needs to test whether or not the browser supports element.addEventListener or element.attachEvent and react appropriately.

var bindEvent = function(elem ,evt,cb) {
    //see if the addEventListener function exists on the element
	if ( elem.addEventListener ) {
		elem.addEventListener(evt,cb,false);
    //if addEventListener is not present, see if this is an IE browser
	} else if ( elem.attachEvent ) {
        //prefix the event type with "on"
		elem.attachEvent('on' + evt, function(){
            /* use call to simulate addEventListener
             * This will make sure the callback gets the element for "this"
             * and will ensure the function's first argument is the event object
             */
             cb.call(event.srcElement,event);
		});
	}
};

Not so bad right? You now have a cross browser way to bind events without all the stuff you don’t need.

Using the Function

This function is really easy to use.

var button = document.getElementById('button');
bindEvent(button,'click',function(e){
    alert(this.value);
});

Test this in IE7+ and your favorite modern browser and see it in action.

Making Your Own Event Tool

One of jQuery’s most attractive features is the syntax. We can mimic this syntax in a simple way and still trim a ton of fat. We will make a simple tool that allows us to cash in on this syntax.

Introducing Boss.js:The Lightweight JavaScript Library

Ok…not really. This is overly simplified, but it demonstrates how easily this can be done. Create a file called boss.js. We are going to use the module pattern to create our library. Explaining all this is a bit beyond the scope of this article, but I will try to comment things for the adventurous. Put the following code in this file:

(function(){
    //the function we just made
	var bindEvent = function(elem,event,cb) {
		if ( elem.addEventListener ) {
			elem.addEventListener(event,cb,false);
		} else if ( elem.attachEvent ) {
			elem.attachEvent('on' + event, function(){
				cb.call(event.srcElement,event);
			});
		}
	},

    //we will use the popular dollar symbol
	$ = window.$ = function(id) {
        //the $ returns a new Boss object
		return new Boss(id);
	},

    //the Boss object constructor
	Boss = window.Boss =  function(id) {
        /* rather than have full selector support, Boss only supports id's
         * boss stores a reference to the elment for later use
         * we explicitly check to see if the id is the window
         * for cases where we want to bind events to the window
         * (something like a load event)
         */
         if ( id === window ) {
             this.elem = window;
         } else {
             this.elem = document.getElementById(id);
         }
    };

    //set up the methods that belong to a Boss object
	Boss.prototype = {
        //this is just a wrapper over our bindEvent function
		bind:function(etype,cb) {
            //use the elem reference
			bindEvent(this.elem,etype,cb);
            //return the Boss object for chaining
			return this;
		},
        //a simple getter setter for style values
		css:function(property,value) {
            //if the property and value are both passed, we are setting the css
			if ( property && value ){
				this.elem.style[property] = value;
            //otherwise we are returning it
			} else if ( property ) {
				return this.elem.style[property];
			}
		}
	};

})();

Save it and Boss.js is born.

Using Boss.js In a Web Page

Setup a simple web page with the following:

<!doctype html>
<html lang="en">
<head>
	<title>JavaScript events</title>
	<script src="./boss.js"></script>
</head>
<body>
	<form action="" method="get">
		<p>
			<input type="button" name="button" value="Toggle Visible" id="button" />
		</p>
		<div id="toggleMe">
			Now you see me!!
		</p>
	</form>
</body>
</html>

Then in the header we will attach to the load event of the window to make sure our document is read. Place the following code in the head section of your document, right below the script element that includes Boss.js:

<script>
$(window).bind('load',function(){
	var toggleMe = $('toggleMe');
	$('button').bind('click',function(e){
		var display = toggleMe.css('display');
		display = (display === "none") ? "block" : "none";
		toggleMe.css('display',display);
	});
});
</script>

The bindEvent function is a simple way to handle events without the whole jQuery library. It’s proof that you can use native JavaScript to accomplish a lot.