Sneaky Abstractions

Subscribe to my Feed, follow me on , recommend me on Working With Rails or see my code on GitHub

Unobtrusive Ajax patterns: element state

Posted on September 11, 2008 17:49 Tagged with unobtrusive, javascript, state, ajax patterns.

I’ve been a little busy lately, so I haven’t had the time to write anything new for my Ajax Patterns series of posts, but I thought I’d write a quick one explaining a simple, maybe obvious, but very useful pattern that I use all the time when dealing with “enhanced” elements. Usually, I wrap HTML elements inside JavaScript objects. This is another mini-pattern that abstracts the behaviour from the content instead of the hit-and-run pattern where elements are located using their IDs or class names, things are done to them and then they’re forgotten. I’ll just give you a quick example of what I mean before I get to the “state” pattern:

var posts = $$('.post').map(function(el){
  return {
    element: el,
    markRead: function(){
      //marks this post as read
    },
    markUnread: function(){
      //marks this post as unread
    },
    isRead: function(){
      //returns true if this post is read
    }
  };
})

With this, we get an array of objects that wrap a “post” element. This is a very common pattern like all the other patterns in this series. The three methods work on this element, but they abstract out the behaviour so you don’t have to touch the element directly. They all deal with state; the state of being read or unread, which has to be stored somewhere. As I’ve wrapped my elements in objects, I could just store the state as an attribute on the object, but HTML already has an excellent way of containing an element’s state: classes. By adding or removing the “read” class on the element, we can store the post’s state. This also means that posts can have an initial state and it’ll just work without us having to do any initialisation magic.

The object now looks like this:

Mysite = {};

Mysite.posts = $$('.post').map(function(el){
  return {
    element: el,
    markRead: function(){
      this.element.addClassName('read');
    },
    markUnread: function(){
      this.element.removeClassName('read');
    },
    isRead: function(){
      return this.element.hasClassName('read');
    }
  };
})

Note that I’ve saved the post objects on a global object Mysite, which means you can get to them later. From here, you could hijack a “Mark as read” form in each post element to use Ajax, and when it’s successfully marked the element as read on the server, it could call markAsRead on itself to change the class. Further, you could have different CSS rules for read and unread posts so that there is a visual feedback to the user that the post has been marked read, which is another great advantage of using class names for state.

This may all seem really obvious, and it is once you start doing it. But I think if you’re a beginner to this whole Ajax business it may not be something you would think about doing. I’ve seen a lot of examples in tutorials and other code where the same functionality would be implemented in a way that the server would send back the entire post element in HTML and the “dumb” client would just replace the content with whatever comes back from the server. There’s really no need to do that when it can be done more efficiently and more scalable. Let the server do its thing without intertwining its responsibilities with that of the client.

Super Disco Breakin