My Other Sites

Friends

Javascript Vs JQuery: Cross Browser Compatibility, Event Handlers, and Selectors August 2nd, 2009

A few days ago I had the pleasure of attending my first Boston Javascript Meetup. It was a pretty good experience, the speaker was decent, but best of all F1lt3r, who I follow on Twitter, was in attendance. He’s been doing work with the new HTML5 and neural networks, and it was pretty exciting stuff. It got me excited about actually learning Javascript. So now, that’s what I’ve started to do. I could always program makeshift Javascript, but I wanted to really learn it this time.

I wanted to do something simple, and I always default to games when I start to learn a new language. They are fairly intuitive and I can come up with simple examples far more easily. Games are also much more fun to create (at this scale, mind you). The game I chose to make was Tic Tac Toe. It is a very simplistic game and took no more than a few hours to make due to my looking up of a lot of stuff. The game is also complex enough to at least touch on a few of the basics of Javascript, from cross browser compatibility issues to event handling to selecting and manipulating elements. Now, I did not use a library right away; I wanted to dig straight into Javascript without knowing what a library could do for me first. I then proceeded to redo the code in jQuery, as I know that I do not want to be dabbling with pure Javascript for too long. I will be breaking the next sections down into how the code looks in Javascript as well as how the code looks in jQuery.

Javascript:

The first thing I needed to learn to forget about for the time being is embedding onclick into my elements in the HTML page. It’s hard to break old habits, but I really wanted to use an even handler in the .js file. The trick of course with event handling is that not all browsers support it the same way. By this I mean, Internet Explorer does things differently from most everyone else.


    // Cross-browser implementation of element.addEventListener()
    function addListener(element, type, func) {
        if(window.addEventListener) { // Standard
            element.addEventListener(type, func, false);
            return true;
        }
        else if(window.attachEvent) { // IE
            element.attachEvent('on' + type, func);
            return true;
        }
        else {
            return false;
        }
    }

addListener(window, "load", init);

This code essentially makes sure the event handler is properly attached to whatever element is passed to it. In this case, as you can see at the bottom of the code, I’m attaching the init function to the load event of the window (the top element of the HTML page). This is because I want to initialize any internal variables I have when the page loads and not before. People make the mistake of thinking their variables can be manipulated when the page first starts loading, and that’s wrong. You need to wait until the page is loaded.


    function init() {
        squares = new Array(3);
        for (var i = 0; i < 3; i++) {
            squares[i] = new Array(3);
        }
        turn = "X";
        $id("message").innerHTML = turn + "'s  turn";
        addListener($tag("table")[0], "click", placePiece);
    }

Init will initialize my internal two dimensional array so that I can keep track of the pieces placed. This makes finding a winner much more convenient later. You will notice that I add a listener to the table. Specifically, I’m listening to clicks in the table that I’m using as my tic tac toe board in the HTML, and I’m calling placePiece() when that click occurs. If you’ve never seen $tag before, that is because I defined a new function called $tag which is just returns document.getElementsByTagName. This is to avoid the hassle of writing that over and over again.


    var $ = {};
    function $tag(tagName) {
        return document.getElementsByTagName(tagName);
    }

The last place where the Javascript gets funky in order to support multiple browsers is in my placePiece function.

    function placePiece(evt) {
        var event = evt || window.event;
        var td = event.target || event.srcElement;
        if (td.innerHTML.indexOf("X") !== -1 || td.innerHTML.indexOf("O") !== -1) {
            $tag("div")[0].innerHTML = "You must place your piece in an empty space!";
            return;
        }
        var tds = $tag("table")[0].getElementsByTagName("td");
        for (var i = 0; i &lt; tds.length; i++) {
            if (tds[i] === td) {
                td.innerHTML = turn;
                squares[Math.floor(i/3)][i%3] = turn;
                findWinner(turn);
                break;
            }
        }
    }

You’ll notice at the top of the function that I have a few ors to properly determine what my event and td variables should be. This is, again, in order to support IE and Firefox and whatever browsers happen to fall in line. The rest is fairly self-explanatory.

jQuery:

The jQuery library takes all of the cross-browser mess and makes it neat and intuitive. Essentially, you no longer have to worry about support unless you stray away from the library. It also simplifies your code SO much. Here is my event handler and init function all rolled up into one function.


    $(function(){
        $("td").live("click", placePiece);
        squares = new Array(3);
        for (var i = 0; i < 3; i++) {
            squares[i] = new Array(3);
        }
        turn = "X";
        $("#message").text(turn + "'s  turn");
    });

This is just like doing $(document).ready(); this is just a shortcut. I don’t want to get into the details of jQuery (if you wanna learn it, simply go to their site!), but you’ll see that I registered the click event on the td’s in the document, and the rest should look fairly similar to the init function I had before. No longer do I have my function to hide the getElementById, jQuery already does that with $(“#id”).

The last noticeable difference is in the placePiece function. Take a look at the top of the function.


    function placePiece(evt) {
        var td = $(evt.target);
        if (td.text().indexOf("X") !== -1 || td.text().indexOf("O") !== -1) {
            $("div:first").text("You must place your piece in an empty space!");
            return;
        }
        var tds = $("td", $("table").get(0));
        for (var i = 0; i &lt; tds.length; i++) {
            if (tds[i] === td.get(0)) {
                td.text(turn);
                squares[Math.floor(i/3)][i%3] = turn;
                findWinner(turn);
                break;
            }
        }
    }

var td = $(evt.target) does everything I had to support multiple browsers, in one line.

So, obviously there is a TON I still need to learn, but I feel this is a good first step. I will continue to compare jQuery and Javascript in order to convince anyone who doesn’t feel like learning a library that they really should.

Let me know in the comments if you’d like a copy of the code.

Edit: Credit goes to Paul Fisher for telling me I didn’t use PRE and to George Adams for telling me jQuery shortcuts and making me not suck too hard on my first real Javascript attempt.