Migrating from prototype to jQuery

I first used Prototype and script.aculo.us on a live in 2007 when I wrote the management interface for gsnowdon.com. At the time they seemed pretty cool and a using the effects and event management functions was a lot better than rolling my own. However, for the last couple of years I’ve been using jQuery for all new sites as I find it’s a much better match for how I write Javascript and it really does seem to require less code in jQuery than doing the same thing in prototype of plain-Javascript. Not only that but the vast selection of jQuery plugins means that in most cases if something I want is not built into jQuery or jQuery UI then there is often a plugin that does the job.

Although I’ve stuck with prototype & script.aculo.us for gsnowdon.com for the last few years my wife has requested a major re-working of the way the product management pages work and I thought that I’d bite the bullet and port the site to jQuery and then use that for all the new functionality.

This post aims to make a very informal comparison of the code between the prototype and jQuery versions of the management pages since that is the most Javascript heavy part of the site and most operations make use of AJAX. Given that gsnowdon.com was one of the first sites I worked on using Prototype the comparison is probably a little unfair as there are probably better ways to write equivalent functionality in Prototype than I used at the time.

The first thing to note is that the management.js file dropped from 948 lines to 802 although some of this is due to differences in the way I tend to format jQuery code. Perhaps a better comparison is file size which dropped from 34,732 bytes to 29,259.

The biggest wins were code fragements such as the following:

1
2
3
4
5
6
7
$A(document.getElementsByTagName("select")).each(
function(value, index) {
if (value.hasClassName("printTypeOptions")) {
value.innerHTML = printTypeOptions;
}
}
);

which become one-liners in jQuery:

1
$('select.printTypeOptions').html(printTypeOptions);

The ability to chain a sequence of jQuery operations also helps to make code more concise, as in:

1
2
3
4
var list = document.getElementById('productList');
...
Element.show(list);
list.innerHTML = "<ul>" + pgHtml.join("") + "</ul>";

Compared to:

1
$('#productList').show().html("<ul>" + pgHtml.join("") + "</ul>");

The original code made quite a lot of use of Prototype’s collect() function as in:

1
2
3
4
5
var pgHtml = $.collect(productGroups,
function(index, value) {
// build HTML string here
}
);

I’d then use join() on the resulting HTML to create a string I could stuff into the innerHTML of a container element. Jquery does not seem to have a collect() function so I used the following implementation from
http://snippets.dzone.com/posts/show/11483

1
2
3
4
5
6
7
8
9
// function replacement for protoype collect function
// http://snippets.dzone.com/posts/show/11483
$.collect = function(c, f) {
var a = [];
$.each(c, function(k, v) {
a.push(f(k, v));
});
return a;
};

The arguments are reversed compared to the prototype equivalent but I like this ordering better.

There’s not a great deal of difference when making AJAX requests between Prototype and jQuery as the following shows; although the ability of jQuery to automatically process JSON and pass an object rather than a string back to the callback did make the code marginally more concise:

1
2
3
4
5
6
7
8
9
10
11
new Ajax.Request(
"mproducts_helper.php?REQ_TASK=listAll&REQ_UNITS="+units,
{
method: "get",
onSuccess: function(transport) {
var response = transport.responseText;
var jsonObj = eval("("+response+")");
parseAllProductItems(jsonObj);
}
}
);

compared to:

1
2
3
4
5
$.ajax({
url: "mproducts_helper.php?REQ_TASK=listAll&REQ_UNITS="+units,
dataType: 'json',
success: parseAllProductItems
});

I could have used $.get() and $.post() to make the jQuery versions a litle bit more concise but didn’t bother in this case.

There were also a number of cases where code like this:

1
$('pageUnits').value;

got re-written as below. The only advantage in doing things the jQuery way in this case is that the code would still work no matter what HTML form widget is used.

1
$('#pageUnits').val();

There’s a lot more I could do to improve the current code. I didn’t make use of any jQuery plugins. For example I could have used Jeditable to replace some home-grown edit-in-place code but that can wait until I start re-working the user interface as I intend to make some significant changes.