First Steps with YUI3

I have used YUI2 quite extensively since I joined Yahoo! in May 2007. Before that I did not really have much experience with any JavaScript library, I had played around with script.aculo.us and jQuery a little bit, but that was all, pretty much. Because here at Yahoo! we, naturally, use YUI in all our projects, I had to dive in and learn how to use it. After a bit of a rough start, figuring out the basics, I started to like YUI2. The reasons why were the modular approach, the good API documentation and, to me, the general way of how to use certain functions seemed pretty logical to me. Now, with the new 3-series coming out, I was curious about what changed, what improved and what to learn in order to use the next generation of the library.

A few major differences

I am not going to go into all the things that are different between YUI2 and YUI3, this is beyond the scope of this post. There is already lots of documentation on YDN and a very good video covering lots of questions like “So whats different?”. Just a few key things to note:

  • YUI3 is majorly different to YUI2. It is basically a new library and thus also, in a lot of ways, works completely different than its predecessor.
  • To avoid conflicts between the two libraries, the global YAHOO object (used in YUI2) is now YUI. This also allows to have both YUI2 and YUI3 on the same page.
  • Every piece of code you write needs to be wrapped in the following statement: YUI().use([YUI3 modules I want to use], function (Y) { ...my code here... } );This, in theory, makes creating namespaces, like we did in YUI2, unnecessary.

A Simple Example: JavaScript Countdown

Just to play around with it and start with a pretty basic example, I wanted to do a countdown in JavaScript. How would I do that using YUI3?

Step by Step

The following steps would need to get executed in order to make this example work:

  1. Put basic markup on the page, which marks the start time of the countdown, e.g. 30 minutes and 0 seconds.
  2. Have one function, decreaseSeconds that decreases the seconds and call this function every second (or 1000 milliseconds).
  3. If the seconds counter reaches 0, decrease the minutes using decreaseMinutes.
  4. Stop the timer if minutes and seconds reach 0.

Basic Markup

As said, the markup on the page already serves as the start time for the countdown and is pretty simple:

<div id="countdown">
        <span id="min">30</span>:<span id="sec">00</span>
</div>

Putting YUI3 on the page

In order to put YUI3 on the page, we need to include the YUI Global Object:

<script src="http://yui.yahooapis.com/3.0.0b1/build/yui/yui-min.js" type="text/javascript"></script> 

And just to verify this is working, we will add some debugging code on the page:

YUI().use("node", function (Y) {
    alert("YUI3 is here!");
});

Just a few words on this. The first argument of the use function, in this case “node”, tells the YUI instance which modules to load. As it will turn out later, the node module, together with the functionality that the YUI global object provides, are enough to make this example work. The last argument here is a callback function, which has the YUI instance as an argument. In this function is where your code lives and has access to the YUI3 instance and modules, if loaded in. More on this in the documentation.

So we got the basics covered, YUI3 is on the page and we can move on to the program logic.

Setting up variables and functions

First I am going to set up some variables that I am going to need throughout the code:

var minutes = Y.get("#min"),
    seconds = Y.get("#sec"),
    timer,
    liftOff = false;

As you can see here, YUI3 gives you the ability to access a DOM element using CSS selectors out of the box. Y.get(“#min”) returns a node (in YUI3 terms) which wraps the underlying DOM object. But be aware that this object here is not the DOM object itself, which is different to what YAHOO.util.Dom.get(“min”) would do.

We will also set up the decreaseSeconds function and the timer:

function decreaseSeconds() {
    // get current seconds value
    var secs = seconds.get("innerHTML");
    
    if (secs === "00") {
        // move to 59
        secs = 59;
        decreaseMinutes();
    } else {
        secs--;
        if (secs < 10) {
            secs = "0" + secs;
        }
    }
    
    if (!liftOff) {
        seconds.set("innerHTML", secs);
    }
}

timer = Y.later(1000, null, decreaseSeconds, [], true);

Instead of talking about the program logic, which should be pretty straight forward, I would like to highlight YUI3 specific things here:

  • Setting up the timer using Y.later is pretty easy and comparable to YAHOO.later in YUI2.
  • As the node returned by Y.get is not the DOM node, doing something like seconds.innerHTML does not work. In fact, it will return ‘undefined’. If you do a console.dir(seconds) you will discover that this does not look like a DOM object at all, but is, as stated above, a YUI node instance wrapping the DOM element with id=”sec”. So instead of doing .innerHTML, we need to use seconds.get(“innerHTML”) to access the content between the opening and closing tag.
  • Likewise, to set content using innerHTML, we need to do seconds.set(“innerHTML”, secs).

This is something to get used to at first. Because in YUI2, people (including me) were used to have the actual DOM object at hand and perform native DOM operations on it. This is not possible anymore with YUI3. It is still possible to access the underlying DOM objects, see Luke’s comment.

After setting this up, we can move on to adding the functionality for decreasing the minutes and making the countdown work.

Making it work

Here is the code and logic for decreasing the minutes and canceling the timer if 0 is reached:

function decreaseMinutes() {
    var mins = minutes.get("innerHTML");
    
    if (mins > 0) {
        mins--;
        if (mins < 10) {
            mins = "0" + mins;
        }
        minutes.set("innerHTML", mins);
    } else {
        timer.cancel();
        liftOff = true;
    }
}

Pretty straight forward and also uses the wrapper methods to access DOM functionality. It works now, but we are not quite finished yet.

Modularizing

As you can see, all the code is currently inline on the page and gets executed as soon as the page loads. This is suboptimal. What I used to do using YUI2 is creating a module specific namespace and then call a public method (made available through the use of the Module Pattern) on the page that needed that functionality. So for this the module would be, e.g.:

YAHOO.Klaus.Countdown = function () {
    ... my code ...
    return {
         init: init
    };
}();

And then, on whatever page I want to use it, do:

YAHOO.Klaus.Countdown.init();

I was curious how to achieve something like this in YUI3.

I came up with a solution but I am not sure if this is the suggested way of doing this. I hope it is, as I couldn’t find a different way of doing it. The secret is to add the “module” you created as a module to YUI3, like:

Y.add("Klaus.Countdown", init);

The second argument is a function name to be executed when the module is being invoked used the use() function.

So what is left to do is saving the countdown code to a separate file and then call the module from within a script block on the page:

<script type="text/javascript">
    YUI().use("Klaus.Countdown");
</script>

So we are done and hopefully happy with our first steps in YUI3.

Conclusion

I have deliberately chosen a simple example to start with to avoid frustrations coming out of having to learn and getting used to too many things at once. Like with every new piece of software, getting started “somehow” in the first place is critical and finding out how to achieve things without running into too many roadblocks at once. How easy or hard it is to use YUI3, I have yet to determine when probably facing more complex examples, but I believe this simple examples gives a sneak peak into what awaits at the end of the line.

This article in other languages

Resources