Data-Driven Templating in One Line

A quick snippet for this happy morning. Actually I’m going to format it so its a couple of lines…

var html = "<li><a href='{profileUrl}'><img src='{photoUrl}'/> {name}</a></li>".replace( /\{([^\}]+)\}/g, function(matches, name) {
  return store.getValue(item, name); 
});


What’s it do? And what does it do that dojo.string.substitute doesn’t? String.replace (a javascript feature, not a dojo thing) accepts a function as its second param. The regexp matches for placeholders in the template string, using the dijit {foo} convention, and returns the value for that field in the data store item.

To see the utility here, lets give it some context, and assume we’re defining an onComplete handler for a dojo.data fetch request.

onComplete: function(items) {
  var re = /\{([^\}]+)\}/g; // cache the regexp object, you're free to use whatever pattern of course
  var htmls = []; // where we'll accumulate the html to represent each item
  var template = '<li><a href="{profileUrl}"><img src="{photoUrl}"/> {name}</a>';
  var store = this.store; // cache a locally scoped reference to the store
 
  dojo.forEach(items, function(item) {
    htmls.push(template.replace(
        re, 
        function(matches, name) {
        // the first argument is the matches object, 
        // subsequent args are your parenthesized sub-matches, equivalent to $1, $2 etc. 
          return store.getValue(item, name);
        }
    ));
  });
  // finally, insert the new content in one go
  this.containerNode.innerHTML = htmls.join("\n"); 
}

Now, the placeholders in the template string are being used as keys to look up values via the dojo.data api, for each store item. The replace function could be written to do some sanity checking. You could also do localization by looking up the values in with dojo.i18n.getLocalization:

  var messageBundle = dojo.i18n.getLocalization("campus.cookie", "exampleBundle", dojo.locale);
  ...
  function(matches, name) {
    var normValue = store.getValue(item, name); 
    return messageBundle[ normValue ] || normValue; 
  }

You’ve given yourself lots of options, its all fast and light on the dependencies, and complements dojo’s api nicely.

Tags: