Simplifying view updates in JavaScript with the Datastore API

Posted by Erik Hope on July 25, 2013

The Datastore API, launched in beta at DBX, provides app developers with an easy way to synchronize data across devices and browsers. By registering change listeners, you can respond in real-time to changes made by other running instances of your app. In the JavaScript library, change listeners are called in response to both local and remote changes. Because all changes trigger the change listener, you can simplify your code by performing all your UI updates from there.

A simple example

To explore this design pattern, let’s consider a simple web app that presents three colored boxes, each with a text field that lets you update the color by typing in a hex color value. The app uses the Datastore API to synchronize changes to the colored boxes across running instances of the app.

Each box is managed by a ColoredBox object in JavaScript. Each ColoredBox object is tied to a record in a datastore. Every time the text field is changed, the record is updated to match by calling the changed method. Note that the color of the box in the UI is not updated at this time. Only the record is changed:

function ColoredBox($el, record) {
    this.$square = $('.color-box', $el);
    this.$textbox = $('input', $el);
    this.record = record;
    this.update();
    this.$textbox.on('focusout', this.changed.bind(this));
}

ColoredBox.prototype.changed = function() {
    this.record.set('color', this.$textbox.val());
};

The ColoredBox object also has an update method, which is used to actually change the UI:

ColoredBox.prototype.update = function() {
    var color = this.record.get('color');
    this.$textbox.val(color);
    return this.$square.css('background', color);
};

Responding to changes

To keep the UI in sync with the records in the datastore, all we need to do is configure a change listener that will call the update method on the appropriate ColoredBox every time a record is changed. This code is set up on initial page load:

datastore.recordsChanged.addListener(function(event) {
    event.affectedRecordsForTable('colors').forEach(function(record) {
        return colored_boxes[record.get('order')].update();
    });
});

Because we’ve triggered update from any record change, this same code handles both local changes from typing in a color and remote changes from another instance of the app.

Try it yourself

You can play with the app in the browser or view the full source code on GitHub.