Recommended Solution
My recommendation is to add an index
key
let data = { "names": [ {"name":"John"},
{"name":"Mary"} ] };
// Add an index manually
data = {
names: [
{ id: 0, name: "John" },
{ id: 1, name: "Mary" }
]
};
// Add an index with a loop
data = data.names
.map(function (name, i) {
name.id = i;
return name;
});
// Nested arrays with indices (parentId, childId)
data = {
names: [{
parentId: 0,
name: "John",
friends: [{
childId: 0,
name: "Mary"
}]
}]
};
Other proposed solutions are not as clean, and suffer from quite a few issues as detailed below.
Problems with proposed Mustache Index solutions
@Index
Mustache does not support @Index
IndexOf
This solution runs in O(n^2) time, and therefore it does not have the best performance. Also the index must be manually created for each list.
const data = {
list: ['a', 'b', 'c'],
listIndex: function () {
return data.list.indexOf(this);
}
};
Mustache.render('{{#list}}{{listIndex}}{{/list}}', data);
Global Variable
This solution runs in O(n) time, so better performance here, but also "pollutes the global space" (i.e. any properties added to the window
object, do not get garbage collected until the browser window closes), and the index must be manually created for each list.
const data = {
list: ['a', 'b', 'c'],
listIndex: function () {
return (++window.listIndex || (window.listIndex = 0));
}
};
Mustache.render('{{#list}}{{listIndex}}{{/list}}', data);
Local Variable
This solution runs in O(n) time, does not "pollute the global space", and does not need to be manually created for each list. However, the solution is complex and does not work well with nested lists.
const data = {
listA: ['a', 'b', 'c'],
index: () => name => (++data[`${name}Index`] || (data[`${name}Index`] = 0))
};
Mustache.render('{{#listA}}{{#index}}listA{{/index}}{{/listA}}', data);