cliff.meyers
cliff.meyers

Reputation: 17734

Is it possible to render dust.js templates synchronously?

I am trying to write an adapter for a client-side HTML/JS templating system to use dust.js under the hood. Unfortunately the API expects render operations to occur synchronously: the rendered output should be returned from the render() call. Dust.js is asynchronous and passes render output to a callback function. Is there any way to work around this, either in the Dust APIs or through some crazy Javascript hack?

Upvotes: 19

Views: 6269

Answers (3)

Amberlamps
Amberlamps

Reputation: 40448

Matt's solution gave me some pointers on how to write a little wrapper that hides the "ugliness" of his solution (by "ugliness" I mean declaring variable outside of callback, assigning value inside callback and returning outside callback).

It not only wraps the hack into a little function but also binds the template´s name. I find this incredible helpful as I find myself using the same render function over and over again, but I do not want to specifiy the template´s name every time.

function templates(template) {
  return function templatesWrapper(data) {
    var result;
    dust.render(template, data, function onRender(err, data) {
      if (err) {
        throw err;
      }
      result = data;
    });
    return result;
  }
}

This is how to use it:

var renderHello = templates('hello.html');
renderHello({ username: 'Stackoverflow' });
// => <h1>Hello, Stackoverflow</h1>

Upvotes: 0

Walter Stabosz
Walter Stabosz

Reputation: 7735

I too wanted to have a function that accepted a context and returned the dust rendered text. Here is the solution I came up with:

// This function sets up dust template, and returns a new function "dusterFn()"
// dusterFn() can be passed a Context, and will return the rendered text.
// @param {String} text: The template text.
// @param {String} [name]: The name of the template to register with dust. If none is provided, a random number is used.
// @param {Function} [onError]: A function that is called if an error occurs during rendering.
function getDusterFn(text, name, onError) {

    var dusterFn = null;
    name = name || Math.floor(Math.random() * 99999).toString();
    onError = onError || function (error) { };

    try {

        var compiled = dust.compile(text, name)
        dust.loadSource(compiled);

        dusterFn = function (context) {
            var dustOutput = '';
            dust.render(name, context, function (error, out) {
                if (error) onError(error);
                dustOutput = out;
            });
            return dustOutput;
        };

    } catch (e) {
        // invalid template syntax 
        e += "\n\nPlease check your template syntax.";
        throw (e);
    }

    return dusterFn;

}

Usage

var greetingTemplate = getDusterFn('Hello {name}, You are {age} years old!');
greetingTemplate({name: 'Jane', age: 24});

Upvotes: 2

Matt Wonlaw
Matt Wonlaw

Reputation: 12443

DustJS is only going to execute things asynchronously when the resources it needs to render (templates, partials) haven't already all been loaded.

If all the dependencies of a template are loaded before you execute that template then it'll execute synchronously (as far as I can tell anyhow). So you can do something like:

var result;
dust.render("tpl", data, function(err, res) {
   result = res;
});
console.log(result); // result will actually already be filled out if dustjs didn't
// have to go look for resources somewhere.

Here is a fuller example below: (and here is a jsfiddle link so you can run it: http://jsfiddle.net/uzTrv/1/)

<script type="text/javascript" src="dust.js"></script>
<script>
    var tpl = dust.compile("Omg {#people} {.} {/people} are here! {>partial/}", "tpl");
    var partial = dust.compile("I'm a partial but I've already been included so things still run {how}", "partial");
    dust.loadSource(tpl);
    dust.loadSource(partial);

    var data = {
        people: ["jim", "jane", "jack", "julie"],
        how: "synchronously!"
    };

    var result;
    dust.render("tpl", data, function(err, res) { 
        result = res;
    });
    console.log(result);
</script>

There could be cases (besides the one I mentioned) where I'm wrong... I don't know everything about dustjs.

Upvotes: 16

Related Questions