How to handle string or array of strings in mustache template

I know it is a bit late, but here is what I use:

{{#test.length}}
    {{#test}}<li>{{.}}</li>{{/test}}
{{/test.length}}

{{^test.length}}
    <li>{{test}}</li>
{{/test.length}}

It's like feature detection. The first block of code checks to see if test has a length, if it does, it is an array (yes, I know strings are supposed to have a length property, too, but they don't). It will either output the array (if it is an array), or nothing (if it isn't). The second block prints out the value of test if it has no length (i.e. it is a string or integer etc) This means you can use it on:

var data = {
    test: "test1"
}

OR

var data = {
    test: [ "test1", "test2", "test3" ]
}

without having to set a flag for whether it is an array or not. Mustache will output both, but the one you don't need will be blank.


I do not know of a way to do this directly from your object without any helper variables. Here is something you COULD do prior to passing the data to the template to avoid having to mess with the code that generates the original JSON object.

Let this be your JSON object:

var data = {
    test: [ "test1", "test2", "test3" ]
}

Let this be your mustache template:

{{#isArray}}
    {{#test}} <li>{{.}}</li>{{/test}}
{{/isArray}}

{{^isArray}}
    {{test}}
{{/isArray}}

Let this be your code that compiles/calls your mustache template (I'm using document.body.innerHTML because that is how I have the JSFIDDLE example set up):

var template = document.body.innerHTML;
document.body.innerHTML = Mustache.render(template, data);

The above setup will print the following out because isArray is undefined, so it will execute the block that negates isArray with the ^ symbol (eg, it will treat the data as a string even if it is an array):

test1,test2,test3

I propose if you do not want to touch the code that is generating the JSON, that you inject some javascript prior to calling Mustache.render to set the isArray property. Here is how I would test for the existence of the pop method in order to set isArray properly before passing the data to the template:

if (data.test.pop) { data.isArray = 1; } else { data.isArray = 0; }
var template = document.body.innerHTML;
document.body.innerHTML = Mustache.render(template, data);

This will properly print out the desired li elements:

test1
test2
test3

I've put a working example here that exercises both the array and string instances in a data element to show that the solution works:

http://jsfiddle.net/s7Wne/1/