In Mustache, How to get the index of the current Section

I am using Mustache and using the data

{ "names": [ {"name":"John"}, {"name":"Mary"} ] }

My mustache template is:

{{#names}}
    {{name}}
{{/names}}

What I want to be able to do is to get an index of the current number in the array. Something like:

{{#names}}
    {{name}} is {{index}}
{{/names}}

and have it print out

John is 1
Mary is 2

Is it possible to get this with Mustache? or with Handlebars or another extension?


Solution 1:

This is how I do it in JavaScript:

var idx = 0;

var data = { 
   "names": [ 
       {"name":"John"}, 
       {"name":"Mary"} 
    ],
    "idx": function() {
        return idx++;
    }
};

var html = Mustache.render(template, data);

Your template:

{{#names}}
    {{name}} is {{idx}}
{{/names}}

Solution 2:

For reference, this functionality is now built in to Handlebars which has compatibility with Mustache.

Use {{@index}}

{{#names}}
    {{name}} is {{@index}}
{{/names}}

John is 0

Mary is 1

Solution 3:

In handlebars.js you can accomplish this with a helper function. (In fact, one of the advantages mentioned about handlebars here http://yehudakatz.com/2010/09/09/announcing-handlebars-js/ is that you can use helpers instead of having to rewrite the objects before calling the template.

So, you could do this:

  var nameIndex = 0;
  Handlebars.registerHelper('name_with_index', function() {
    nameIndex++;
    return this.name + " is " + nameIndex;
  })

And, then your template can be this:

{{#names}}
<li>{{name_with_index}}</li>
{{/names}}

Your data is the same as before, i.e.:

{ "names": [ {"name":"John"}, {"name":"Mary"} ] };

And you get this output:

<li>John is 1</li>
<li>Mary is 2</li>

To make this really work, nameIndex needs to get reset each time the template is rendered, so to do that you can have a reset helper at the beginning of the list. So full code looks like this:

  var data = { "names": [ {"name":"John"}, {"name":"Mary"} ] };
  var templateSource = "<ul>{{reset_index}}{{#names}}<li>{{name_with_index}}</li>{{/names}}</ul>";
  var template = Handlebars.compile(templateSource);

  var helpers = function() {
    var nameIndex = 0;
    Handlebars.registerHelper('name_with_index', function() {
      nameIndex++;
      return this.name + " is " + nameIndex;
    });
    Handlebars.registerHelper('reset_index', function() {
      nameIndex = 0;
    })
  }();

  var htmlResult= template(data);
  $('#target').html(htmlResult);

  var htmlResult2= template(data);
  $('#target2').html(htmlResult2);

(This can correctly render the template twice.)