Handlebars/Mustache - Is there a built in way to loop through the properties of an object?
Javascripthandlebars.jsMustacheJavascript Problem Overview
As the title of question says, is there a mustache/handlebars way of looping through an object properties?
So with
var o = {
bob : 'For sure',
roger: 'Unknown',
donkey: 'What an ass'
}
Can I then do something in the template engine that would be equivalent to
for(var prop in o)
{
// with say, prop a variable in the template and value the property value
}
?
Javascript Solutions
Solution 1 - Javascript
Built-in support since Handlebars 1.0rc1
Support for this functionality has been added to Handlebars.js, so there is no more need for external helpers.
How to use it
For arrays:
{{#each myArray}}
Index: {{@index}} Value = {{this}}
{{/each}}
For objects:
{{#each myObject}}
Key: {{@key}} Value = {{this}}
{{/each}}
Note that only properties passing the hasOwnProperty
test will be enumerated.
Solution 2 - Javascript
It's actually quite easy to implement as a helper:
Handlebars.registerHelper('eachProperty', function(context, options) {
var ret = "";
for(var prop in context)
{
ret = ret + options.fn({property:prop,value:context[prop]});
}
return ret;
});
Then using it like so:
{{#eachProperty object}}
{{property}}: {{value}}<br/>
{{/eachProperty }}
Solution 3 - Javascript
EDIT: Handlebars now has a built-in way of accomplishing this; see the selected answer above. When working with plain Mustache, the below still applies.
Mustache can iterate over items in an array. So I'd suggest creating a separate data object formatted in a way Mustache can work with:
var o = {
bob : 'For sure',
roger: 'Unknown',
donkey: 'What an ass'
},
mustacheFormattedData = { 'people' : [] };
for (var prop in o){
if (o.hasOwnProperty(prop)){
mustacheFormattedData['people'].push({
'key' : prop,
'value' : o[prop]
});
}
}
Now, your Mustache template would be something like:
{{#people}}
{{key}} : {{value}}
{{/people}}
Check out the "Non-Empty Lists" section here: https://github.com/janl/mustache.js
Solution 4 - Javascript
This is @Ben's answer updated for use with Ember...note you have to use Ember.get
because context is passed in as a String.
Ember.Handlebars.registerHelper('eachProperty', function(context, options) {
var ret = "";
var newContext = Ember.get(this, context);
for(var prop in newContext)
{
if (newContext.hasOwnProperty(prop)) {
ret = ret + options.fn({property:prop,value:newContext[prop]});
}
}
return ret;
});
Template:
{{#eachProperty object}}
{{key}}: {{value}}<br/>
{{/eachProperty }}
Solution 5 - Javascript
@Amit's answer is good because it will work in both Mustache and Handlebars.
As far as Handlebars-only solutions, I've seen a few and I like the each_with_key
block helper at https://gist.github.com/1371586 the best.
- It allows you to iterate over object literals without having to restructure them first, and
- It gives you control over what you call the key variable. With many other solutions you have to be careful about using object keys named
'key'
, or'property'
, etc.
Solution 6 - Javascript
Thanks for Ben's solution, my use case to display only particular fields in order
with object
Code:
handlebars.registerHelper('eachToDisplayProperty', function(context, toDisplays, options) {
var ret = "";
var toDisplayKeyList = toDisplays.split(",");
for(var i = 0; i < toDisplayKeyList.length; i++) {
toDisplayKey = toDisplayKeyList[i];
if(context[toDisplayKey]) {
ret = ret + options.fn({
property : toDisplayKey,
value : context[toDisplayKey]
});
}
}
return ret;
});
Source object:
{ locationDesc:"abc", name:"ghi", description:"def", four:"you wont see this"}
Template:
{{#eachToDisplayProperty this "locationDesc,description,name"}}
<div>
{{property}} --- {{value}}
</div>
{{/eachToDisplayProperty}}
Output:
locationDesc --- abc
description --- def
name --- ghi
Solution 7 - Javascript
This is a helper function for mustacheJS, without pre-formatting the data and instead getting it during render.
var data = {
valueFromMap: function() {
return function(text, render) {
// "this" will be an object with map key property
// text will be color that we have between the mustache-tags
// in the template
// render is the function that mustache gives us
// still need to loop since we have no idea what the key is
// but there will only be one
for ( var key in this) {
if (this.hasOwnProperty(key)) {
return render(this[key][text]);
}
}
};
},
list: {
blueHorse: {
color: 'blue'
},
redHorse: {
color: 'red'
}
}
};
Template:
{{#list}}
{{#.}}<span>color: {{#valueFromMap}}color{{/valueFromMap}}</span> <br/>{{/.}}
{{/list}}
Outputs:
color: blue
color: red
(order might be random - it's a map) This might be useful if you know the map element that you want. Just watch out for falsy values.
Solution 8 - Javascript
I was using old version 1.0.beta.6
of handlebars, i think somewhere during 1.1 - 1.3 this functionality was added, so updating to 1.3.0 solved the issue, here is the usage:
Usage:
{{#each object}}
Key {{@key}} : Value {{this}}
{{/people}}