Ervadac
Ervadac

Reputation: 956

How to handle default value as partial parameters in dust.js?

I actually made a simple dust partial and I would like to give it some parameters with default value. Not very easy to explain but here is a simple example:


Partials

partials/hello.dust

{?label}{label}{:else}Hello{/label}: 
<span>{?name}{name}{:else}World{/name}</span>

partials/hello2.dust

{>"partials/hello"/} and 
{>"partials/hello" label="{label2}" name="{name2}"/}</div>

Examples of how it should work

test_0.dust

{>"partials/hello2" label="Peter" name="Parker" label2="Clark" name2="Kent"/}

Returns: "Peter:Parker and Clark:Kent"

test_1.dust

{>"partials/hello2" label2="Clark" name2="Kent"/}

Returns: "Hello:World and Clark:Kent"

test_2.dust

{>"partials/hello2" label="Peter" name="Parker"/}

Returns: "Peter:Parker and Hello:World"

test_3.dust

{>"partials/hello2"/}

Returns: "Hello:World and Hello:World"


In partials/hello.dust, if label & name variables are not defined, they are replaced with default values (respectively "Hello" and "World")

So here, test_0.dust and test_1.dust will work since I provide label2 and name2 parameters.

In partials/hello2.dust, I don't know if this is possible to do this an elegant way but I would like a different default value for label2 and name2 variables so it is not mandatory to provide them either ("Hello2" and "World2" for example).

One solution I can think of would be to handle all possible combinations in hello2.dust including the partial accordingly (i.e. label2 empty and name2 empty, label2 empty and name2 not empty, label2 not empty and name2 empty, label2 not empty and name2 not empty) but it can be pretty painful and ugly as you can see.

To be clear I would like to be able to do something like this:

partials/hello2.dust

{>"partials/hello"/}
{>"partials/hello" label="{?label2}{label2}{:else}Hello2{/label2}" name="{?name2}{name2}{:else}World2{/name2}"/}


SOLUTION

In case it would help someone, I finally made my own dust helper:

'use strict';

module.exports = function (dust) {
    dust.helpers.default = function (chunk, ctx, bodies, params) {
        var resData, paramVals = {}, saveData = chunk.data;

        var localCtx = ctx;
        if (params) {
            localCtx = ctx.push(params);
        }
        for (var key in bodies) {
            if (key !== 'block') {
                chunk.data = [];
                resData = bodies[key](chunk, localCtx).data.join('');
                if (typeof ctx.get(key) === 'undefined') {
                    paramVals[key] = resData;
                }
            }
        }
        chunk.data = saveData;
        return bodies.block(chunk, localCtx.push(paramVals));
    };
};

So, it can be used like this:

{@default}
{>"partials/mypartialusingname1"/}
hello {name1} & {name2} 
{:name1}Chuck Norris
{:name2}Walter White
{/default}

Then, if name1 and name2 does not exist in the current context it is replaced by some default values.

Upvotes: 1

Views: 1341

Answers (2)

adamduncan
adamduncan

Reputation: 168

We solved this problem by creating a similar helper. Using key value attributes in a single @defaults helper declaration.

Parent template

<!-- Standard partial include -->
{>"components/module-promo" /}

<!-- Partial include with overrides -->
{>"components/module-promo" title="Custom title override" caption="Custom caption" /}

Partial

{@defaults
    title="Module title"
    caption="Module caption ipsum dolor sit amet."
/}

<article>
    <h2>{title}</h2>
    <p>{caption}</p>
</article>

Helper

dust.helpers.defaults = function(chunk, context, bodies, params) {
    for (var key in params) {
        context.global[key] = params[key];
    }
    return chunk;
};

(Remember to return the chunk from the helper function.)

This works really well for synchronous template rendering. We store our values on context.global, and add/modify them as the partials compile. This means global is mutated, but we do avoid issues with multiple partials using the same parameter names.

The approach would run into trouble if attempting to stream/async the template renders. Maybe someone could elaborate on the best way to store partial-specific context values to improve this?

Upvotes: 1

Interrobang
Interrobang

Reputation: 17434

Dust does not include a facility for setting default values for a context.

This would be a job for a Dust helper. A naïve version of this helper might look like this:

Template

{@defaultParam key="hello" value="moo"/}
{@defaultParam key="world" value="world"/}
{hello} {world}

Context

{
    "hello": "hello"
}

Helper

dust.helpers.defaultParam = function(chunk, context, bodies, params) {
  var key = params.key,
      value = params.value;

  if(typeof context.get(key) === 'undefined') {
    context.global[key] = value;
  }
};

Upvotes: 2

Related Questions