Thursday, July 21, 2005

I just AJAX'ed my Struts 1.1 web application - in about an hour (or not...)

Before AJAX (version 1.0)

At one of my client sites, we have built an internal web application with a
relatively complex interface - corporate look and feel wrappering our web application which has a right-hand side tabbed context bar, plus the main area of the page provides a tabbed interface, with tabs up to three levels deep. We are using Struts tiles to assemble the page, with the main area and the right hand side area being seperate tiles - if the main tab changes, it might change the right hand context, and navigating through tabs on the right hand side generally don't affect the main area. A heavily used area of the application has the right hand side displaying some detailed information about an item selected in the main area. The user can select different items in the main area, and this updates the right hand side.

This caused a full page refresh, which could take a good number of seconds for
each new item selected.

Prototyping & AJAXing - Version 1.1

As a test, I saved the rendered output of one of the pages, wrapped the sidebar
in a div, and wrote some javascript that would update the div with the contents of another webpage when a link was pressed. It worked (or at least appeared
to work), and I almost immediately began to think about how I would write up
that switching my entire web application to an AJAX infrastructure to update
the main body or sidebar was done super-easily, because the tiles of my
web application could be retrieved independently as required, and we could use a div's innerHTML to render new content.

It turns out I was jumping the gun a bit - getting the sidebar AJAX'd involved updating the links for the tabs, to kick off an AJAX request - no problem, and
the performance for the user was huge - the corporate look and feel is great looking, but relatively large, involving many stylesheets, some javascript code, etc - and changing a tab in the past meant a full page reload, which on my 6 year old sun workstation could take 10 seconds - and now it was almost instantaneous. Even better, I didn't have to make any of the main body or template files, just to the jsp code that rendered the 10 or so sidebars. I hit two problems:

1) Some of the sidebars were missing some of the dynamic changes on the page - I thought that perhaps the XmlHttpRequested pages were not passing the session cookie, but it turns out this was not the case - there was an error in the HTML, and the browser wasn't rendering the sidebar as expected when the sidebar was requested via XmlHttpRequest, and updated via innerHTML. After figuring this out, and correcting the html error, the sidebars began rendering correctly.

2) If as the user was working within the web application, and regularly changing
sidebar tabs, the sidebar began to get out of sync with the state of the web application. It turns out that something (browser?, XmlHttpRequest object?) was caching the contents of the sidebar, so I used the cache-busting technique of appending a pseudo-random number to the url - by updating the getNewSidebar javascript code.

I then began working on getting the main area of the page to update with
XmlHttpRequest for tab changes as well - this was hindered and effectively
stopped by the fact that:

1) The tabs on the main area of the page weren't rendered on each main tile, but
were in fact rendered in the corporate look and feel template - so the tabs
were not refreshing properly. To fix this would require placing the tab rendering code in all of the main body tiles, and removing it from our template - not impossible - but not a fun task.

2) The way that our stylesheet was written to render tabs forced us to keep one
of our tags unclosed within the main body (and giving the sidebar, which is rendered in a different tile)

In Summary

We decided to use AJAX just for the right hand sidebar for the time being. There were limited changs required to implement this change. The performance improvements were significant to users. We were able to use our existing Struts actions and jsps for tiles to quickly cut over to AJAX by wrappering a tile area in a <span> and then using innerHTML to update / refresh that area. Being on a corporate Intranet, we knew that just 2 browser version were supported (IE 6 and Mozilla 1.4), simplifying testing of the application.