Search code examples
dust.js

Indirection in dust.js


Is it possible to achieve variable indirection in dust.js - and therefore to be able to use map-like functionality?

Imagine I have the following context to pass to Dust:

{
  "keys": [ "Foo", "Bar", "Baz" ],
  "data": [{
      "date": "20130101",
      "values": {
        "Foo": 1,
        "Bar": 2,
        "Baz": 3
      }
    }, {
      "date": "20130102",
      "values": {
        "Foo": 4,
        "Bar": 5,
        "Baz": 6
      }
    }]
}

And I want to achieve the following output (it would actually be a table, but I've skipped the <tr><td> tags for brevity and replaced them with spaces and newlines):

Date Foo Bar Baz
20130101 1 2 3
20130102 4 5 6

I'm not sure how to loop over the keys property, and use each value x to look up data[i].values[x]. I can get the desired output by hardcoding the keys:

Date{~s}
{#keys}
  {.}{~s}
{/keys}
{~n}
{#data}
  {date}{~s}
  {values.Foo}{~s}
  {values.Bar}{~s}
  {values.Baz}{~s}
  {~n}
{/data}

but the keys will be determined dynamically, so I can't hardcode them into the template. Is there a way to replace the lines that say values.Foo etc., with something like the following:

{#data}
  {date}{~s}
  {#keys outerMap=values}
    {outerMap.{.}}{~s}
  {/keys}
  {~n}
{/data}

This doesn't work as written; can I capture the output of {.} (the value of the current key) and dynamically use it as (part of) the property name to resolve?


Solution

  • As smfoote says, this is not supported out-of-the-box in Dust.

    However, I've realised that handlers can involve some elements of logic, and so it was relatively straightforward to write a handler to do dereferencing:

      deref: function(chunk, context, bodies, params) {
        chunk.write(params.obj[params.prop]);
      }
    

    This handler takes an obj argument which is the object to use as an associative array; and the prop parameter describing the key to look up from that object. With this handler function added to the context, I was then able to write the data part of the template as:

    {#data}
      {date}{~s}
      {#keys}
        {#deref obj=values prop=./}{~s}
      {/keys}
      {~n}
    {/data}
    

    This produces the correct output, by iterating over every key and passing it in as the property to read from the values object.

    I appreciate that some might consider this inappropriate given Dust's philosophy. However I don't think it constitutes particularly complex logic; indeed, it's something that could quite conceivably be part of a templating framework. Given that smfoote's suggested alternative of updating my JSON isn't an option (the template does not know what the keys will be in advance, so there is no way to write "static" references here), this seems like a reasonable approach.