- Introduction
- Comparison Chart
- Dojo
- MochiKit
- Yahoo User Interface
- Scriptaculous + Prototype
- jQuery
- Author
- Thanks to
Introduction
This is an evaluation of 5 different Javascript libraries.
We want to check for the following things:
- Browser compatibility
- Django integration (if relevant)
- Ease of use
- Maturity and Support
- Overall quality
- Documentation
- AJAX capabilities and handling (XML, JSON)
- DOM manipulation
- widgets: integrate datetime picker, autocomplete field, tabber interface, table sortable by any column field.
Comparison Chart
| Dojo | MochiKit | YUI | prototype | jQuery | |
| JSON Support | 10 | 10 | 8 | 6 | 10 |
| Error callbacks | 10 | 10 | 10 | 10 | 7 |
| Logging | 5 | 10 | 10 | 0 | 7 |
| Autocomplete | 6 | 0 | 9 | 5 | 8 |
| Sortable table | 4 | 0 | 8 | 0 | 7 |
| calendar | 8 | 0 | 7 | 0 | 9 |
| tabs | 9 | 0 | 8 | 0 | 8 |
| tree view | 7 | 0 | 8 | 0 | 0 |
| event management | 7 | 9 | 9 | 7 | 9 |
| stop event propagation | 10 | 10 | 10 | 6 | 10 |
| stop default behaviour | 10 | 10 | 10 | 6 | 10 |
| DOM ready event | 10 | 10 | 10 | 10 | 10 |
| CSS DOM selection | 10 | 10 | 0 | 10 | 10 |
| DOM creation | 0 | 10 | 5 | 0 | 10 |
| DOM insertion | 0 | 10 | 7 | 10 | 10 |
| DOM replacement | 0 | 10 | 4 | 10 | 10 |
| DOM update | 0 | 10 | 7 | 10 | 10 |
| get/set x,y position relative to viewport | 0 | 8 | 10 | 0 | 10 |
| get/set x,y position relative to document | 0 | 8 | 10 | 0 | 0 |
| Articles, tutorials | 7 | 5 | 8 | 7 | 8 |
| API docs | 4 | 9 | 9 | 8 | 9 |
| External support | 10 | 4 | 8 | 8 | 7 |
| Periodic calls | 0 | 6 | 0 | 8 | 0 |
| Drag and Drop support | 5 | 7 | 8 | 8 | 8 |
| Back button handling | 8 | 0 | 9 | 0 | 7 |
| Personal opinion | 7 | 8 | 8 | 5 | 9 |
| Total | 147 | 174 | 200 | 134 | 203 |
(Addition by Nate Koechley, a YUI team member at Yahoo!, email address natek at yahoo-inc dot com: I want to point out that as of YUI 2.4, released 2007.12.04, YUI now has a Selector utility that allows DOM collections based on CSS Selectors. Prior to the 2.4 release YUI did not offer this functionality, which is why we received 0 points for this features in the above chart and totals. More info on the 2.4 release and Selector: http://yuiblog.com/blog/2007/12/04/yuii-240/)
Dojo
AJAX
It has a couple of methods, dojo.xhrGet and dojo.xhrPost to do AJAX requests; they take a dictionary, where it is specified the URL to request, the GET/POST params -if any- and the success and error callback. It is possible to pass all the data of the form in the page, through the `form` attribute.
It can handle data formatted as JSON; it uses a dictionary-like object to access the response's data. E.g.
function response_handler(response, ioArgs) {
alert(response.first_param);
}
Pretty simple and straightforward.
Widgets
The approach is simple: load some CSS and import the definitions of the given widget. To make a Django use the functionality of Dojo widgets it is only necessary to set a proper HTML tag attribute on the Django widget (dojoType)
date = forms.DateField(widget=forms.TextInput(attrs=dict(dojoType="dijit.form.DateTextBox")))
and do the CSS and JS imports on the template
<style type="text/css">
@import "/static/dojo/dijit/themes/tundra/tundra.css";
@import "/static/dojo/dojo/dojo.css";
</style>
<script type="text/javascript" src="/static/dojo/dojo/dojo.js" djConfig="parseOnLoad: true"></script>
<script type="text/javascript">
dojo.require("dojo.parser");
dojo.require("dijit.form.DateTextBox");
</script>
Tab support is handled as a <div> acting as a tab container, with inner <div>s, each one holding the content of a tab. Autocomplete support for widgets is available as well, through AJAX or using local completion (like the values of a SelectField), and the HTML code only needs some extra attributes to get it working. Dojo has a SortableTable as well, but it seems underdocumented.
Compatibility
Supports IE6, Firefox and Opera. It claims to support Konqueror, but it failed the AJAX test on it. All the tested widgets (tab, calendar, autocomplete) worked properly on all the browsers except Opera. Googling a bit it looks like the current version of Dojo will cease supporting both Opera and Konqueror, although I haven't found any official statement about that.
Maybe the "we support all these browsers" is another example of sloppy docs :(
My Opinion
I hate not having proper documentation available.
On the other hand, the widget mechanism (adding custom attrs to elements) is quite simple to use and integrates itself well with Django. Most of the functionality works as you would expect it to do. But, honestly, I'm afraid of trying something that is not on the book. JSON support out of the box, extra points. But not so good on compatibility. I would not use it.
MochiKit
AJAX
MochiKit provides functions to do requests for both XML and JSON formats. These functions require an URL and, optionally, a dictionary holding the GET parameters for the request. They return a Deferred object, which provides a point to define the proper callbacks. For example
var d = loadJSONDoc("/index/get_user_data/", {username: $("id_username").value});
d.addCallbacks(handle_req, error_req);
The called callback receives an object holding the result of parsing the server's request to the proper format. Pretty simple to use.
Event Handling
The connect function allows connection of events to specified callbacks. It receives the DOM element to monitor (or its id string), the event, and the callback.
connect("id_username", "onchange", make_request);
Quite similar to other toolkits, and resembles concepts from GUI programming.
Widgets
MochiKit doesn't bundle any widget on it; at least not widgets similar to YUI's or Dojo. It has a module for visual effects, and other for color specification, but no widgets. This is by design; MochiKit is aimed to provide a better JS programming environment, not a lot of widgets. Unfortunately, in this case.
Maturity and Support
The general opinion on Internet is that MochiKit is quite well designed; it is fully documented and properly tested. I agree with this opinion.
On the other hand, MochiKit is written mostly by one person (Bob Ippolito). Yet, it is used on some large projects (TurboGears). The development is not very active, apparently because MochiKit is feature-complete.
DOM Manipulation
Excellent. It provides CSS selectors, functions to create DOM elements (really convenient), update their attributes, insert, replace, or delete them. An example taken from the official docs:
var rows = [
["dataA1", "dataA2", "dataA3"],
["dataB1", "dataB2", "dataB3"]
];
row_display = function (row) {
return TR(null, map(partial(TD, null), row));
}
var newTable = TABLE({'class': 'prettytable'},
THEAD(null,
row_display(["head1", "head2", "head3"])),
TFOOT(null,
row_display(["foot1", "foot2", "foot3"])),
TBODY(null,
map(row_display, rows)));
swapDOM(oldTable, newTable);
To help DOM element creation, it provides a mechanism called DOM Coercion Rules that ease this task a lot. Finally, it is easy to manipulate retrieved elements with the functional programming tools bundled in MochiKit.
Yahoo User Interface
AJAX
YUI provides the asyncRequest function; it takes the method (GET or POST), the url, an object (dictionary) with functions to manage the response from the server (success entry), manage errors (failure entry), pass arguments to these functions (argument entry), and pass arguments to the request (to the server)
var callback =
{
success:responseSuccess,
failure:responseFailure,
argument:args
};
var transaction = YAHOO.util.Connect.asyncRequest('GET', sUrl, callback, server_args);
On a successful request, the callback.success function is called, and an object is passed as argument. It contains info about the request, and in particular the full string returned by the server. To parse the response to JSON
Works properly with all tested browsers.
Event Handling
Straightforward for DOM events
var oElement = document.getElementById("d-e-e__");
function fnCallback(e) { alert("click"); }
YAHOO.util.Event.addListener(oElement, "click", fnCallback);
It can also attach a handler to the same event for multiple objects; instead of passing a DOM node it is possible to pass an array of Element IDs. It provides too a method to stop event propagation, like handling the click of an and not following the link.
Works properly with all tested browsers.
Widgets
Getting Django newforms to use YUI widgets is not as straightforward; since most widget presentation involves creating new elements, the YUI widgets asks for a <div> to hold the new elements, thus making Django widgets a bit cumbersome to use directly. It should be possible to use Django newforms by creating new widget classes or modifying the way a form is rendered; since it provides methods to render itself as table or list, it should be possible to define a new render which generates the needed <div>s. Yet, it seems more easy to subclass :D.
The autocomplete field needs to be inside a <div> and have another <div> to hold the suggestions. To make it have an autocomplete it is necessary to create a data store to define where to get the data, and an AutoComplete object associating the input field, the data store, and the <div> needed to hold the results. It won't work with the default Django widgets (newforms), but it is possible to subclass a widget and generate the needed <div>s and Javascript code, and should not require much effort. Yahoo's example doesn't work with Opera.
The calendar field requires an id to the table on which the calendar will be created, and an extra <div> id to show the calendar in there. The rest of the setup involves creating a JavaScript event handler that associates the calendar with an input field. Is a bit cumbersome, since you would expect that the calendar widget is already doing so. Works properly on all browsers.
Sortable tables are somehow easy to use: they need a dataSource properly initialized, column definitions (titles of each column) and the id of the <div> that will act as a container.
Tabs are handled as a <div> which acts as a the tab container, and a list (<ul>) of tab titles along with another <div> which holds the contents of each tab, each one of them inside of (yes, another) <div>. Works properly on all tested browsers.
DOM Manipulation
Provides methods to get and set the (x,y) position of any element, whether in the context of the HTML document, or of the current viewport.
Provides methods to select elements by tag name, by class, or by id. It is possible to define a filter function and a node to use as root for the tree search. It has also functions to get siblings, childrens, insert elements before or after a given element.
Works properly on tested browsers.
My Opinion
It has everything you might need, but with different levels of refinement. The widgets are quite powerful, yet they don't seem to have the behaviour that you would expect from them, e.g., the calendar widget. One area where I feel YUI is weak is DOM manipulation.
All the widgets that I've seen require extra <div>s to render themselves. This is good (because you define exactly where do you want the widget to render) and bad (because it requires modifying the underlying HTML document in a non-trivial fashion).
Docs are excellent. A really big plus for it. I would use it. Although it doesn't feel as natural as using Dojo, and requires a bit more effort to learn than other toolkits.
Finally, widgets don't work in Opera. Bad thing. And odd, since the other stuffs (events, AJAX) work just fine.
(ADDITION: Hello, this is Nate Koechley from the YUI Team at Yahoo!. I'm curious about your Opera comment. Can you be more specific? According to our extensive test everything in YUI works perfectly in Opera; we treat Opera as an "A-Grade" browser: http://developer.yahoo.com/yui/articles/gbs. Thanks, Nate (natek at yahoo-inc dot com). )
Scriptaculous + Prototype
Documentation
It has introductory articles with basic concepts and examples, and a complete API documentation. No complaints at all. There is a book on Prototype + Scriptaculous: http://books.pragprog.com/titles/cppsu
AJAX
It not only provides the traditional handlers to make asynchronous requests to the server (XML and JSON), but it also packs functions to update containers: you give them the id of a container (e.g., a <div>), and it will make the request, fetch the HTML the server returns, and update the contents of the container with it. There is even a function to update content every certain time, with cute details to make the requests less frequent when the content doesn't change.
To handle JSON, the string class has a new method called toJSON which can be used to parse the server's response.
Event Handling
The Event object provides a an observe method. The method signature is this
Event.observe(element, eventName, handler[, useCapture = false])
Yet, the documentation is not clear about what is sent to the handler when the event occurs. Apparently the received Event object has methods to get info from the event parameter.
It provides a function to stop event propagation and prevent default behaviour. It does both things, and I'm not quite sure if this is a good thing to do.
Widgets
Prototype does not provide any widgets or controls. However, scriptaculous does. It features an autocomplete widget, which receives an HTML string with an unordered list of elements. It also has support for drag and drop.
It has no sortable table, calendar widget, or tab management. The docs are a bit chaotic on the scriptaculous side, so I might be missing something.
DOM Manipulation
Prototype extends the Element object with its own methods. This is convenient to do things like this example (adding a class to an element and show it):
$('comments').addClassName('active').show()
These methods are designed to chain them, allowing things like the above. However, this has a drawback, since not all Elements are extended. $('div_id') returns an extended element; `Form.getElements` and the $$ function do the same as well. However, a newly created DOM element (document.createElement('h2'), e.g.) is not an extended element, and it must be extended (with Element.extend or $) to get the prototype methods.
Scriptaculous complements this methods with the Builder object, which allows to create DOM elements in an easy fashion.
My Opinion
IMHO, it is bad designed. A good example is the JSON parsing; it should not be a method of the string class, but a function, or an option in the AJAX method. Same goes with the extension the the DOM elements. Not so good.
Prototype is focused on putting most of the processing load on the server; this can be seen on the approach of functions like the periodical updater, or the autocomplete field, since they get from the server an HTML fragment, instead of a JS array or dictionary. It is a different approach, yet it is not my favorite.
(Not an edit but a mistake, Prototype does JSON parsing automatically. It only needs the content to be loaded on an application/json content-type [which is not hard and the right way to do it]. And then the JSON object will be available on Ajax.Response#responseJSON see: http://www.prototypejs.org/api/ajax/options evalJSON)
jQuery
AJAX
It provides proper methods for doing async requests and handling JSON. The syntax is simple
$.getJSON("test.js", { name: "John", time: "2pm" }, function(json){
alert("JSON Data: " + json.users[3].name);
});
It requires an url, the params for the request, and a proper callback.
It can also load HTML into a given Element. You indicate the id of the element, and it makes the request and updates the element with the text returned on the response.
Event Handling
To add an event handler you select the element(s) and then call the bind method, providing the event description and the callback. Like this (again, taken from the official docs):
function callback (e) {
var str = "( " + e.pageX + ", " + e.pageY + " )";
$("span").text("Click happened! " + str);
}
$("p").bind("click", callback);
This approach allows binding a callback for an event on many DOM elements at once. If you need to define an event handler only for one element, simply select it by its id.
Widgets
jQuery does not have widgets by itself; there is another project called jQuery UI that fills this gap. It features a tab manager, a calendar widget, sortable tables, drag and drop support, etc. Widgets like the autocompletion input are available as plugins. A Django widget can be made a jQuery widget in a straightforward way: selecting the input element, and calling the proper method on it. Like this
$('#example').calendar();
DOM Manipulation
Excellent. jQuery uses the "chaining" concept, where you select elements, and have methods to apply over them. The application of these methods returns another set of elements, upon which you can apply more methods. An example taken from the official docs:
$("a").addClass("test");
that adds the class test to all the elements. Another a bit more elaborated
$("a").addClass("test").show().html("foo");
this does the same as before, and shows the elements, and replaces their html content. You can filter the list too, attach listeners to events, apply functions to each element, and so on. It has CSS and XPath selectors. The modification, insertion, deletion, and replacement of DOM elements is quite easy and accesible as well.
Last update: 2010-02-03 (Rev 16652)