14 Sep 2007
Undo Made Easy with Ajax (Part 1)
As users, we make mistakes. As designers, we need to design with mistakes in mind, as I argued in my recent article, Never Use a Warning When You Mean Undo. Undo is the ultimate safety net, lending an incredible sense of solidity to an interface. That’s why every desktop application from Word to Photoshop provides multiple-level Undo.
So, then, why are Web apps that provide any sort of Undo so few and far between? The answer I often get is that Undo is hard to implement. I’m here to tell you that it is not.
In this series of blog posts, my goal is to explain just how easy it is to provide Undo functionality. Recently, I gave a preliminary version of this post in a workshop. After giving the front-facing demo of how Undo could work, the audience moved slightly towards the edge of their seats (it’s all you can hope for in the post-lunch session). When I opened the source code and started showing how I implemented undo, the universal response was, “Why are you bothering to explain this implementation? It’s barely anything at all. We’re software engineers. This is easy.”
That’s my point!
Adding Undo to your interfaces profoundly and positively affects the usability of your site. It reduces user frustration, and increases user trust. Both of those outcomes mean that more users continue coming back, which helps your bottom line. Remember: To the user, the interface is the product.
Now you have no excuse to not implement Undo. So, without further ado, here’s the first implementation method.
Method 1: The Event Queue
The situation: You are creating an online to-do list, and the user needs to be able to delete any item in the list. You don’t want the user to delete an item accidentally, nor do you want them to be unable to change their mind after a delete or two (this second requirement is a stronger version of just being able to recover from the “ohnosecond” I described in my earlier article). The method currently employed across the Web is to warn the user with a dialog box.
Even 37 Signals, normally a bastion of good design, uses warnings instead of undo.
Not only does this warning not work — it also locks up the Web browser, requiring a decision before being able to switch tabs. If you need to check your email in order to figure out whether you can delete a to-do, you are out of luck.
Try out the to-do list with the standard (but not very humane) warning dialog box solution.
Now say that you change your mind about deleting something, or you want to delete 3 items in a row. Sort of frustrating, isn’t it?
The correct solution is Undo, which we can implement here with an event queue and an “onUnload” callback. When the user clicks delete, the to-do item disappears. Normally, at this point we would send an AJAX request to the server to actually delete the item. When writing for Undo, instead of immediately sending the AJAX call, we delay until the user navigates away from the current page (which we detect using the “onUnload” callback). This is achieved by placing a reference to the to-do item in the event queue for safe keeping.
When a user clicks Undo, we pop the last item added to the event queue and make the related to-do item visible again. When the user navigates away from the page, or closes it, the “onUnload” event gets called. It’s at this point that we iterate through the event queue and send the AJAX requests to server-side delete the to-do items.
One of the big benefits of using the event queue method is that it makes multi-level Undo almost trivial. And it also makes deleting a whole bunch of to-do items painless (which is not the case when deletes cause warnings). Try it out!
The Source Code
Intrigued? Want to know more? Good. Here’s the documented source code.
The event queue method of implementing Undo isn’t perfect:
- If the user’s browser or computer crashes, then the user’s work will be lost. This is clearly not optimal. On the other hand, this is a rare circumstance and can be safely ignored for all but life-and-death important data.
- Real-time collaboration won’t work with this method of Undo because changes are not sent to the server until the user exits the page. Thus, other users will not see updates in anything approximating real time. Other methods of implementing Undo get around this problem, but that will have to wait until another post in this series.
- It is inadvisable to use this Undo method for sending emails or other time-sensitive actions. Because the action only gets completed when the user exits the page, it might take half an hour or longer before the email actually gets sent. That isn’t acceptable.
- [Update] Reader Alexander Botero-Lowry pointed out that if you deleted items in the to-do list and then opened up the page in a new tab, those items would seem to magically re-appear. To learn how to solve this problem, read Undo Made Easy with Ajax (Part 1.5).
As you have seen, Undo does not have to be a time-consuming undertaking. The event queue method can even be done entirely client-side, which means that you can implement Undo without changing a thing about your back end.
So, no more excuses about Undo being difficult to implement. It’s time for Undo to make its way onto the web!
Next week, I’ll show how to tackle Undo for time-sensitive actions.
by Aza Raskin