Handlebars/Mustache - Is there a built in way to l

2019-01-01 15:03发布

问题:

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
}

?

回答1:

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.



回答2:

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 }}


回答3:

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



回答4:

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 }}


回答5:

@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.


回答6:

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


回答7:

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.



回答8:

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}}