AjaxPatterns
This is the original book draft version for the Update Control Ajax pattern, offered for historical purposes and as an anti-spam measure.
You're probably better off visiting the Live Wiki Version for Update Control instead, where you can make changes and see what others have written.

Update Control

Backwards, FastForward, Forwards, Freeze, Pause, Push, Refresh, Rewind, Reverse, Speed, Sticky, Update

Goal Story

Sasha's entranced by a world map continuously updating with events from around the world. She plays around with the velocity controls, first speeding it up so there's a new event every second (no matter how trivial), then backtracking through previous events, and finally pausing on something that catches her eye.

Problem

How can the user deal with continuous information entering the browser and updating the page?

Forces

  • Many Ajax Apps continuously grab data from the server and place it on the page.

  • The web page has a limited area, meaning that you'll need to remove or relegate older content.

  • The optimum speed of updating depends on the user and their task. It should be fairly quick if the user is actively monitoring, for example, and probably quite slow if it's a bit of eye candy at the edge of a page.

Solution

Let the user control the rate and criteria of updates. Using patterns like “HTTP Streaming” and “Periodic Refresh”, it's possible to keep grabbing fresh content from the server, so you can show news updates, system events, and so on. We're seeing this more and more, with photo slideshows, news updates, and so on, and it can easily lead to information overload. This pattern is about giving the user control over the incoming stream of information and takes several forms.

First, the user can control the rate of change, pausing rewinding, and fast-forwarding. Pausing is important for several reasons. First, it gives the user an ability to reflect on the content. Second, it lets them keep the content open while perform some work related to it. Third, it lets them interact with the content, in the case that it contains links or other forms of control. This is a serious issue in interfaces like Digg Spy which stream new links every second or so. Go to click a link and - BAM! - it's already been replaced by a new link by the time your mouse pointer gets there.

Rewinding is useful too, to let people see something they didn't catch the first time, or to let them revisit something in the light of new information.

Fast-forwarding is another form of Update Control. More generally, this relates to setting the speed of updates - to something faster or slower than the application's default. This way, users can tailor behaviour to their own needs and the task they're performing. Different users will have different mental processing capabilities and preferences - some are hungry for a torrent of incoming data, others prefer a more casual pace. Furthermore, how is the information being used? In one case, the user might be actively watching the information, such as a trader monitoring company news. In another case, the user might be trying to find an interesting story to go and read while viewing a list of new RSS items. Instead of second-guessing how the user's using all this content, the advice here is to set a suitable default rate but give them the power to change it.

In theory, you only need a single "speed control" to allow for Update Control. A negative speed corresponds to rewind, zero to pause, one to default speed, and a high number for fast-forward. This could be set with a “Slider” or an input field or both. However, you can probably do a better job than that. The media player metaphor is particularly compelling, given how closely it relates to this problem as well as how universal the concepts are. You can also opt to be a bit clever about controlling the speed, adapting to the user's behaviour. If the mouse is hovering near some content, that's probably a good clue to pause it, especially if the content is interactive.

You can also let the user choose what kind of content will be shown, which is an indirect way of influencing the rate. For example, a user might select between "Critical", "Informational", and "All". Or the criteria may be more domain-specific, as with Digg Spy, which provides checkboxes against the kinds of things you want to monitor - new stories, new comments, and so on.

Real-World Examples

Digg Spy

Digg Spy shows new stories and events such as user moderation as they happen (see Figure 1.4, “Digg Spy” in “Display Morphing”). The information can change so quickly that it's difficult to click on a link, but fortunately, a pause button is present. In addition, you can indirectly control how fast the content appears by tweaking the filtering options, so, for example, you can ask Digg to only show you new story submissions.

Slide

Slide shows a stream of visual content from Flickr, EBay, and elsewhere (Figure 1.78, “Slide”). A "-" button moves content leftwards, a pause button pauses it, and a "+" button speeds it up. It will also pause when you hover the mouse over it. The rolling slideshow is implemented with Flash, but the idea is equally applicable to pure Ajax.

Figure 1.78. Slide

Slide

WBIR

WBIR, a regional news provider, sometimes shows "slideshow images" (Figure 1.79, “WBIR.com Image”). Like animated GIFs, these are a sequence of several images, one at a time, in the same container. But unlike animated GIFs, you can click to pause a single image.

Figure 1.79. WBIR.com Image

WBIR.com Image

Code Example [Digg Spy]

Digg Spy includes a pause and a play button in the initial HTML. At any point in time, exactly one of these buttons is active and will respond to a click, which is registered to notify the togglePause() function. togglePause() doesn't actually check which button the event originated from, because it instead tracks the pause mode with an explicit pause variable. Thus, the first task of togglePause() is to toggle the state of the pause variable.

    function togglepause() {
      pause = !pause;
      ...
    }

If we've just entered pause mode, togglepause() cancels the timers used to make the updates. Otherwise, it does the exact opposite, i.e. schedules the updates, as well as making an initial update.

    function togglepause() {
      ...
      if (pause == 1) {
        clearInterval(timer);
        clearTimeout(timer2);
        ...
      } else {
        update();
        timer = setInterval('addaline(true)', scrollDelay); 
        timer2 = setTimeout('update()', updateDelay);
      }
      ...
    }

The last thing togglepause() does is to call write_pause, which updates the container (play-pause-toggle) containing both buttons. The HTML is mostly the same in both cases, but the hyperlink to togglepause() changes place according to which button should be active.

    function write_pause() {
      if (pause == 0) {
        document.getElementById('pause-play-toggle').innerHTML = '<span class="spy-play"><strong>Play</strong></span><a href="#" onclick="togglepause()" class="spy-pause">Pause</a></span>';
      } else {
        document.getElementById('pause-play-toggle').innerHTML = '<a href="#" class="spy-play" onclick="togglepause()"><strong>Play</strong></a><span class="spy-pause"><strong title="Pause the display of new items.">Pause</strong></span>';
      }
    }

Related Patterns

“Periodic Refresh” is one means of keeping page content fresh, hence a situation where you might use Update Control.

Like “Periodic Refresh”,“HTTP Streaming” is a pattern which keeps page content fresh, the situation where Update Control applies.

Metaphor

Think of the navigation controls on a DVD player.

Acknowledgements

Thanks to Christopher Kruslicky for suggesting a pattern based around pausing, which ultimately led to this pattern.

Live Wiki Version for Update Control