In Mustache, How to get index of current section

I use Mustache and using data

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

My mustache pattern:

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

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

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

and print it

 John is 1 Mary is 2 

Can I get it from Mustache? or with pens or other extension?

+48
templates mustache
Feb 16 2018-11-21T00:
source share
10 answers

For reference, this functionality is now built into Handlebars, which is compatible with Mustache.

Use {{@index}}

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

John = 0

Mary 1

+28
Nov 25 '12 at 21:16
source share

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}} 
+38
Apr 18 '12 at 11:18
source share

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

So you can do this:

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

And then your template might be as follows:

 {{#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> 

For this to work, nameIndex must receive a reset each time the template is rendered, so for this you can have a reset helper at the top of the list. Thus, the complete code is as follows:

  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 may correctly display the template twice.)

+13
Feb 22 2018-11-21T00:
source share

You can run the next cycle in the list of objects.

This solution has the following advantages:

  • Does not change model data
  • Index can be accessed several times

The code:

 for( var i=0; i< the_list.length; i++) { the_list[i].idx = (function(in_i){return in_i+1;})(i); } 

Explanation:

Instead of the variable name, a function is used, so the data is not mutated. Closing is used to return the value of "i" during the creation of the function in the loop instead of the value i at the end of the loop.

+7
Sep 23
source share

Great helper here:

 // {{#each_with_index records}} // <li class="legend_item{{index}}"><span></span>{{Name}}</li> // {{/each_with_index}} Handlebars.registerHelper("each_with_index", function(array, fn) { var buffer = ""; for (var i = 0, j = array.length; i < j; i++) { var item = array[i]; // stick an index property onto the item, starting with 1, may make configurable later item.index = i+1; // show the inside of the block buffer += fn(item); } // return the finished buffer return buffer; }); 

Source: https://gist.github.com/1048968

+5
Nov 05 '11 at 20:10
source share

The best approach for Mustache would be to use a function that gets the index using indexOf :

 var data = { names: [ {"name":"John"}, {"name":"Mary"} ], index: function() { return data.names.indexOf(this); } }; var html = Mustache.render(template, data); 

In your template:

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

The downside is that this index function has an array of hard-coded data.names , to make it more dynamic, we can use another function like this:

 var data = { names: [ {"name":"John"}, {"name":"Mary"} ], index: function() { return function(array, render) { return data[array].indexOf(this); } } }; var html = Mustache.render(template, data); 

Use in your template:

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

Also a small drawback is that you must pass the array name of the index function in this example names , {{#index}}names{{/index}} .

+3
Oct 26 '14 at 15:43
source share

If you can control the output of a JSON string, try this.

 { "names": [ {"name":"John", "index":"1"}, {"name":"Mary", "index":"2"} ] } 

Therefore, when you create a JSON string, add the index as another property for each object.

+1
Feb 16 '11 at 20:14
source share

My main use case for this was the ability to place an "active" class on elements. I teamed up with combining the equals helper with the index_for_each helper, but it was too complicated.

Instead, I came up with the following basic β€œactive” helper. This is very specific, but is such a common use case for any menu / select scenario:

Using:

  <ul> {{{active 2}}} {{#each menuItem}} <li class="{{{active}}}">{{this}}</li> {{/each}} </div> 

Would make the 3rd menu item "class =" active ".

Helper here (this is CoffeeScript version):

 active = 0 cur = 0 handlebars.registerHelper 'active', (item, context) -> if arguments.length == 2 active = item cur = 0 '' else if cur++ == active 'active' 
+1
Sep 06
source share

As long as you are not traveling in multiple arrays, you can store the index in the helper and simply increase it when the context changes. I am using something similar to the following:

 var data = { foo: [{a: 'a', 'b': 'a'}, {'a':'b', 'b':'b'}], i: function indexer() { indexer.i = indexer.i || 0; if (indexer.last !== this && indexer.last) { indexer.i++; } indexer.last = this; return String(indexer.i); } }; Mustache.render('{{#foo}}{{a}}{{i}}{{b}}{{i}}{{/foo}}', data); 
+1
Jun 29 '13 at 0:23
source share

(Tested in node 4.4.7, mustache 2.2.1.)

If you need a nice clean functional way that doesn't include global variables or mutates the objects themselves, use this function;

 var withIds = function(list, propertyName, firstIndex) { firstIndex |= 0; return list.map( (item, idx) => { var augmented = Object.create(item); augmented[propertyName] = idx + firstIndex; return augmented; }) }; 

Use it when you collect your presentation;

 var view = { peopleWithIds: withIds(people, 'id', 1) // add 'id' property to all people, starting at index 1 }; 

The best approach to this approach is that it creates a new set of viewmodel objects using the old set as prototypes. You can read person.id just as you would read person.firstName . However, this function does not change your people objects at all, so other code (which may have relied on the ID property while not there) will not be affected.

O (N) algorithm, so nice and fast.

0
Jul 21 '16 at 9:25
source share



All Articles