For my current open source project I have to create a JavaScript application that runs in all major web browsers. Until now I spent most of my time to develop Java applications on the server side. And if I did some JavaScript I just copied an existing example and modified it to my specific needs. So it was really cool to have a reason to learn about JavaScript, its libraries and possibilities
Here I want to share my experiences with JavaScript and the Yahoo! User Interface (YUI) library.
Because of the browser differences I thought it is a good idea to base my development on a solid, well tested library. After a short investigation time, I decided to have a closer look at the following alternatives:
For each of the libraries I created some small prototypes, read the documentation to get a feeling about the concept and possibilities. After this evaluation phase it was clear for me, that the Yahoo! user interface (YUI) library is by far the best framework for my needs. Compared to the other frameworks it uses the full power of the JavaScript language, and offers a library and a concept that enables you to create big JavaScript applications. I don’t go into further detail on Prototype and GWT here, and concentrate this blog on YUI. If you are interested in my experience with the other two frameworks, just contact me.
For an experienced Java developer it takes a little bit to get familiar with the language specifics of JavaScript. Unfortunately I did not find one good JavaScript book
Therefore here the most important concepts.
JavaScript Basics
Objects
It is very important that you understand the syntax and behavior of objects, because you find them everywhere. Let’s start with a simple example:
var person = {
firstName: "Markus",
lastName: "Tripp"
};
There are other ways an object can be created, but object are usually created using the curly brackets { }. Then think about an object in JavaScript as a kind of hash table, with key/value pairs. Where key is a string and value can be anything from string, function, or a nested object. To get the first name of the person object above, call: person.firstName.
Like with a hash table, any object can be extended by simple assigning new members. Let’s add a nested address object and a toString function to the above created person object.
person.address = {
city: "Salzburg",
country: "Austria"
};
person.toString = function() {
return firstName + " " + lastName;
}
If you would have created the entire person object in the beginning, it looks like this:
var person = {
firstName: "Markus",
lastName: "Tripp",
address: {
city: "Salzburg",
country: "Austria"
},
toString: function() {
return firstName + " " + lastName;
}
};
Additionally objects are very often dynamically created as parameters for functions. For instance, if you have a function called addPerson that expects a person object as an argument, you often see it programmed this way:
addPerson({
firstName: "Markus",
lastName: "Tripp"
});
This just calls the addPerson function and passes an object with the attributes firstName and lastName. Of course this object may contain nested objects and functions. It’s also possible that you pass arrays or functions as parameters for functions. For instance if you pass a persons toString method to the logPerson function this would look like this:
logPerson(function(person) {
return person.firstName + " " + person.lastName;
});
That’s basically all you have to understand to start working with objects. As you can see, JavaScript does not have Java’s static typing and strong type checking.
Functions
Functions inherit from Object and therefore can store name/value pairs. As you saw before, functions can be passed as arguments, returned from other functions, or just stored like other values. The following two examples define the same function:
function addPerson(person) {
...
};
var addPerson = function addPerson(person) {
...
};
Arrays
Like functions, arrays also inherit from Object. This means arrays have the same characteristics, you can store any other object or function as values, and it can be extended like any other object. One difference is, that indexes are converted as strings and used as names to retrieve the values. Here a simple example:
var names = ["Markus", "Harry"];
var i;
for (i = 0; i < names.length; i += 1) {
var name = names[i];
// do something with the name
}
Scope and Closure
It is essential that you understand scope and closure, to understand most of the existing JavaScript examples and libraries.
Scope: An inner function has access to the variables and parameters of functions that it is contained within.
Closure: The scope continues, even after the parent function has returned.
For additional information and details about JavaScript and advanced language concepts like inheritance I recommend that you watch the videos from Douglas Crockford about JavaScript at the YUI Theater page.
Yahoo! User Interface (YUI) Library
After some basics about the JavaScript language, I discuss here some basics about the YUI framework. When evaluating the 3 framework options, I was really impressed, what the Yahoo! developers created. A stable library with an easy to understand concept and lot’s of documentation and examples.
One of the things YUI always mention is, that global variables are evil.
<script>
var name = "Markus";
</script>
When you embed the above script into a web page, the variable “name” is global, and can be accessed and modified everywhere. For a simple mouseover script this is OK, but if you have a rich JavaScript application, or even worse if you use external JavaScript applications, this variable can be accessed or modified by all scripts. Therefore YUI has only one global variable, and stores everything within this object. The object is called YAHOO. For your projects I recommend to use the same concept by using the namespace function of the YAHOO global object. For instance my personal projects have one global MEXT object.
var MEXT = YAHOO.namespace("mext");
So, we have something that is similar to a package in Java. Now it would be helpful to have something like a class to structure the application. YUI usually use the term “module pattern”. I think I best describe the YUI module pattern with a simple example. I create a class AsyncLoader that has one public method load. The load method loads HTML content from a server asynchronously and inserts the HTML in a given div tag. Except that the server returns HTML instead of XML this is a real AJAX example (AJAX stands for Asynchronous JavaScript and XML). In the HTML page the call looks like this:
<div id="content">Loading...</div>
<script>
var loader = new MEXT.AsyncLoader();
loader.load("content", "proxy?service=latestNews");
</script>
var loader = new MEXT.AsyncLoader() instantiates the class and loader.load(…) executes the load method, which calls proxy?service=latestNews on the server and inserts the result in the div above with the name “content”. Why do I call a proxy service on my server? Because of security restrictions of modern browsers it is not allowed to make AJAX calls to external resources directly. One way to workaround this is passing the request through a proxy. Read more about this here. Additionally this gives you some nice possibilities, like caching of the remote call responses, pre and post processing.
Now let’s have a look at the JavaScript class I created using the module pattern.
File: ajax.js
var MEXT = YAHOO.namespace(”mext”);
(function() {
// private member variables
var Dom = YAHOO.util.Dom;
var Connect = YAHOO.util.Connect;
// private functions (methods)
var handleSuccess = function(response) {
var element = Dom.get(response.argument.id);
element.innerHTML = response.responseText;
}
var handleFailure = function(response) {
var element = Dom.get(response.argument.id);
element.innerHTML = response.status;
}
// Class constructor
MEXT.AsyncLoader = function() {
// empty constructor
};
// Public methods of class
MEXT.AsyncLoader.prototype = {
load: function(divId, url) {
var callback = {
success: handleSuccess,
failure: handleFailure,
argument: { id: divId }
};
var transaction = Connect.asyncRequest(
“GET”, url, callback, null);
}
};
})();
In this simple example you see how to create a class, add private members and methods, and add public methods.
(function() {
...
})();
This is just required to be sure that nothing within this function is global. Because global is evil as we learned. Therefore the code is incapsulated in a function and the brackets around just ensures that the code inside the function is initialized and executed. This function does not get executed:
function() {
...
};
Create private members and private functions. Because of the scope described before, those variables can be used also in the inner functions.
Create a class constructor, and then all public methods within the objects prototype. For more information about the Object.prototype and other advanced JavaScript concept I recommend watching the videos on the YUI theater page.
I’m working with JavaScript intensively for 2 weeks now, and I really have to tell you, if you have experience in programming languages (e.g. Java) and understand the above example, you can do pretty everything.
To complete the example, here the entire HTML. It demonstrates another extremely cool YUI part, the YUI CSS foundation. Usually the web pages have a column based layout. If you code always everything from scratch this can be quite an effort to support all the major browsers. The YUI CSS foundation and especially the YUI CSS grids provides you a kind of standard to come over this problem very quickly and easily.
File: ajax.html
<!DOCTYPE html PUBLIC “-//W3C//DTD HTML 4.01 Strict//EN”
“http://www.w3.org/TR/html4/strict.dtd”>
<html>
<head>
<title>Ajax Example</title>
<meta http-equiv=”Content-Type”
content=”text/html; charset=UTF-8″ />
<link rel=”stylesheet” type=”text/css”
href=”http://yui.yahooapis.com/2.5.0/build/
reset-fonts-grids/reset-fonts-grids.css” />
<link type=”text/css” href=”screen.css” />
<script src=”http://yui.yahooapis.com/2.5.0/build/yahoo/
yahoo-min.js”></script>
<script src=”http://yui.yahooapis.com/2.5.0/build/event/
event-min.js”></script>
<script src=”http://yui.yahooapis.com/2.5.0/build/connection/
connection-min.js”></script>
<script src=”http://yui.yahooapis.com/2.5.0/build/dom/
dom-min.js”></script>
<script src=”ajax.js” mce_src=”ajax.js”></script>
</head>
<body>
<div id=”doc2″ class=”yui-t2″>
<div id=”hd”>
Header
</div>
<div id=”bd”>
<div id=”yui-main”>
<div class=”yui-b”>
<h1>Content</h1>
<div id=”content”>Loading…</div>
<script>
var loader = new MEXT.AsyncLoader();
loader.load(”content”,
“proxy?service=latestNews”);
</script>
</div>
</div>
<div class=”yui-b”>
Navigation
</div>
</div>
<div id=”ft”>
Footer
</div>
</div>
</body>
</html>
The above used CSS id’s and classes create a 950px width centered page (<div id=”doc2″>) with a header, body and footer. The body consists of two blocks (columns - yui-t2), one 180px column on the left which is the navigation and a second column which is the main block and contains the main content. Additionally you could nest additional columns in the main content using grids. This all with cross browser support and without writing one line CSS. Brilliant.
I think as a starting point this is enough. As a next step I recommend to go to the YUI home page, discover the examples and dig into the YUI source code. An excellent place to learn.
Quite interesting is, that for my current open source project I use quite some technologies, where Yahoo! has its hands on, YUI (JavaScript + CSS), Flickr, OpenID, Lucene, Firebug. Thanks, Yahoo! I hope, I can give you something back at some time 