solnic on blog web development, ruby, javascript and other crazy things

15Jan/098

Client-side rendering with Prototype

Web applications are getting more and more complex. The user interface of a modern web application can be as rich as its desktop equivalent. If we use JavaScript/HTML/CSS trio to build this UI then we definitely want to use AJAX. A typical approach is to use AJAX to update parts of our page using an HTML response, everyone knows that, right? Does this approach allow us to create a responsive, fast and flexible UI? The answer is no.

Here are 4 main downsides of using AJAX requests to load UI parts:

  • You increase the server load – yes, you make an AJAX request only because you need a piece of HTML code that you want to insert to an already rendered page. That was cool a few years ago when AJAX was such a great innovation. Nowadays it should be considered as a less efficient solution.
  • You complicate the server-side code – because you need parts of your page to be returned by the server you, obviously, need to handle that by writing more server-side code. You end up having many actions in your controllers that return different fragments of HTML. I know, you think it’s normal, everyone does that.
  • You loose a lot of control over the UI – you use DHTML techniques to deal with the UI and in the same time you need the server to get parts of that UI. This leads to a code duplication and in many cases ends up with a big mess.
  • A user will have to wait until a request is done – that just sucks, that poor guy has to wait because you went back to the server for a little piece of HTML. How you are going to implement a responsive UI this way? “Your servers are fast”. Of course they are, but what if user’s ISP sucks? What if the user is downloading something and 99% of his bandwidth is gone?

Rendering HTML on the client-side is ridiculously simple. Consider the following example. Let’s say we have a page with a list of some people, the list is just a simple HTML table. It could look like this:

<table>
  <thead>
    <tr>
      <th>First Name</th>
      <th>Last Name</th>
      <th>E-Mail</th>
    </tr>
  </thead>
  <tbody id="people">
    <!-- here go people -->
  <tbody>
  <tfoot>
    <tr colspan="4">
      <td>
        <a id="previous" href="#">Previous</a> 
        <a id="next" href="#">Next</a>
      </td>
    </tr>
  </tfoot>
</table>

As you can see the tbody element is empty, we will load its content after the entire page is loaded. Instead of a bunch of “tr” elements the server should return a nice JSON data which could look like this:

var people = [
 { id : 1, first_name : 'John', last_name : 'Doe', email : 'john.doe@somewhere.com' },
 { id : 2, first_name : 'Jane', last_name : 'Doe', email : 'jane.doe@anywhere.com' },
 { id : 3, first_name : 'Third', last_name : 'Guy', email : 'third.guy@nowhere.com' }
];

To render these data we obviously need a template. Prototype gives us a handy class called Template which is perfect for our needs. To create a template and render the list of people we need a few lines of JavaScript:

var personRowTemplate = new Template(
  '<tr id="person_#{id}"><td>#{first_name}</td><td>#{last_name}</td><td>#{email}</td></tr>');
 
var peopleRows = '';
 
people.each(function(person) { 
  peopleRows += personRowTemplate.evaluate(person); 
});
 
$('people').update(peopleRows);

That’s pretty much it. It doesn’t look spectacular, huh? Now just think about the benefits of this approach:

  • You have the data in JSON format, you can use them to render things like an edit form without going back to the server, thus user experience will be better
  • You can be focused on building a nice JSON API for accessing data instead of implementing actions that return small pieces of HTML
  • Your client-side code is cleaner and more consistent

Sounds like a good deal, doesn’t it? :)

Comments (8) Trackbacks (0)
  1. Sounds good, although I don’t like one thing – if Javascript is disabled, then you won’t see anything. You should keep it unobtrusive :) Probably a better way would be to write this so that the initial data is rendered inside , you can move between pages using plain HTML, but if Javascript is available, then it will be used for enhancing the UI by downloading JSON and rendering HTML using templates. Although that would mean there will be two parts of code for rendering the same thing (in JS and in the view code on the server)…

    “And if you are authoring a site, and make it unreadable without Javascript, you are shooting yourself in the foot.” (http://www.xs4all.nl/~sbpoley/webmatters/whatnojs.html)

  2. Oh, and one more thing – Google will not index any data rendered this way…

  3. Thanks for the comments Kuba.

    We’re talking about web apps here – desktop apps replacements and JS is a requirement. Web sites content indexing, SEO, progressive enhancement, accessibility etc. is a different topic.

    BTW, I wonder if it’s possible to access…I dunno, Gmail for instance, without JS turned on.

  4. I’ve just tried – it just shows “loading”, but there’s a link below to an HTML-only version which works very well.

  5. But how well would this scale? If you had say 500 elements with complex HTML would using Template be a viable option as it has some rather large overheads?

  6. You really don’t want to render 500 complex elements on one page in the same time. You probably want to use a pagination or load more elements dynamically as a user scrolls down (something like in Google Reader).

    Of course it all depends on what you’re going to render, in some cases 500 elements wouldn’t be a problem. It also depends on what you’re doing with the elements while you’re rendering them. For instance you might want to modify some of them on-the-fly, attach various event listeners and so on, this could take a lot of CPU time. But as I wrote, you don’t want to render 500 elements in the same :)

  7. You might not want to, but some times you have too! Take a File Manager for example that would need to show a large amount of files even if you paginated it.

  8. It’s not a problem to have a lot of elements rendered on the same page, so what I mean is that you shouldn’t render all of them in one loop, b/c it would take a lot of CPU time. As a solution you can use lazy rendering, as far as I remember YUI’s DataTable uses this trick when it comes to large amounts of data.


Leave a comment


No trackbacks yet.