Guidon / Moustache - Existe-t-il un moyen intégré de parcourir les propriétés d'un objet?


216

Comme l'indique le titre de la question, existe-t-il un moyen moustache / guidon de parcourir les propriétés d' un objet ?

Donc avec

var o = {
  bob : 'For sure',
  roger: 'Unknown',
  donkey: 'What an ass'
}

Puis-je ensuite faire quelque chose dans le moteur de modèle qui serait équivalent à

for(var prop in o)
{
    // with say, prop a variable in the template and value the property value
}

?

Réponses:


448

Prise en charge intégrée depuis le guidon 1.0rc1

La prise en charge de cette fonctionnalité a été ajoutée à Handlebars.js, il n'y a donc plus besoin d'aides externes.

Comment l'utiliser

Pour les tableaux:

{{#each myArray}}
    Index: {{@index}} Value = {{this}}
{{/each}}

Pour les objets:

{{#each myObject}}
    Key: {{@key}} Value = {{this}}
{{/each}}

Notez que seules les propriétés qui réussissent le hasOwnPropertytest seront énumérées.


2
@Rafi: on ne peut pas donner beaucoup de sens à cela sans connaître votre structure de données.
Jon

3
@Rafi: tu ne veux pas dire {{this.title}}?
Nevyn

2
@qodeninja: Simple: de la même manière que vous vous référez aux valeurs dans les exemples ci-dessus - avec {{#each this}}. Votre choix de termes est également déroutant (qu'est-ce qui fait qu'un objet est "de niveau supérieur" et pas un autre? Quelles sont exactement les clés "prédéfinies", etc.), donc vous voudrez peut-être revoir ces concepts.
Jon

1
si ce n'est pas le cas, alors seulement avec la v1.1.0, c'est disponible, mais merci pour la bonne réponse.
Renars Sirotins

2
Comment procédez-vous uniquement pour une liste blanche spécifique de propriétés?
Marco Prins

70

Il est en fait assez facile à implémenter comme aide:

Handlebars.registerHelper('eachProperty', function(context, options) {
    var ret = "";
    for(var prop in context)
    {
        ret = ret + options.fn({property:prop,value:context[prop]});
    }
    return ret;
});

Ensuite, utilisez-le comme ceci:

{{#eachProperty object}}
    {{property}}: {{value}}<br/>
{{/eachProperty }}

2
Ça a l'air bien, avez-vous besoin d'ajouter une vérification hasOwnProperty à l'intérieur de la boucle pour ne pas itérer sur les propriétés du prototype?
monkeyboy

Grande solution @Ben. Dans le cas où quelqu'un essaie d'utiliser cela avec Ember, voir ma réponse ci-dessous pour la solution pour le faire fonctionner.
flynfish

27

EDIT: le guidon a maintenant une manière intégrée d'accomplir cela; voir la réponse sélectionnée ci-dessus. Lorsque vous travaillez avec de la moustache ordinaire, ce qui suit s'applique toujours.

La moustache peut parcourir les éléments d'un tableau. Je suggère donc de créer un objet de données séparé formaté de manière à ce que Moustache puisse fonctionner avec:

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]
     });
  }
}

Maintenant, votre modèle de moustache serait quelque chose comme:

{{#people}}
  {{key}} : {{value}}
{{/people}}

Consultez la section "Listes non vides" ici: https://github.com/janl/mustache.js


1
J'ai fini par suivre votre suggestion car je dois de toute façon passer quelques propriétés supplémentaires. Merci pour l'aide!
Ben

Merci beaucoup, votre idée m'a sauvé une autre journée de recherche d'alternatives. Cette ligne est la clé moustacheFormattedData = {'people': []};
Matt

Comment feriez-vous cela avec un tableau d'objets "o"?
red888

4

Ceci est la réponse de @ Ben mise à jour pour une utilisation avec Ember ... notez que vous devez l'utiliser Ember.getcar le contexte est transmis sous forme de chaîne.

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

Modèle:

{{#eachProperty object}}
  {{key}}: {{value}}<br/>
{{/eachProperty }}

Merci @flynfish. le contexte est une chaîne dans Ember ?? cela semble .. quelque peu étrange.
Ben

Oui, je ne suis pas vraiment sûr depuis que je suis nouveau sur Ember et que j'essaie toujours de trouver mon chemin.
Flynfish

1

@ La réponse d'Amit est bonne car elle fonctionnera à la fois sur la moustache et sur le guidon.

En ce qui concerne les solutions réservées aux guidons, j'en ai vu quelques-unes et j'aime mieux l' each_with_keyassistant de blocage sur https://gist.github.com/1371586 .

  • Il vous permet d'itérer sur les littéraux d'objets sans avoir à les restructurer au préalable, et
  • Il vous permet de contrôler ce que vous appelez la variable clé. Avec de nombreuses autres solutions, vous devez faire attention à utiliser des clés d'objet nommées 'key', ou 'property', etc.

Belle trouvaille. Juste un avertissement pour les autres lecteurs: l'assistant "key_value" de cet élément contient un bogue. Lisez les commentaires pour savoir comment y remédier.
sirentian

0

Merci pour la solution de Ben, mon cas d'utilisation pour afficher uniquement des champs particuliers afin

avec objet

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

Objet source:

   { locationDesc:"abc", name:"ghi", description:"def", four:"you wont see this"}

Modèle:

{{#eachToDisplayProperty this "locationDesc,description,name"}}
    <div>
        {{property}} --- {{value}}
    </div>
    {{/eachToDisplayProperty}}

Production:

locationDesc --- abc
description --- def
name --- ghi

0

Il s'agit d'une fonction d'aide pour moustacheJS, sans pré-formatage des données et au lieu de cela lors du rendu.

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

Modèle:

{{#list}}
    {{#.}}<span>color: {{#valueFromMap}}color{{/valueFromMap}}</span> <br/>{{/.}}
{{/list}}

Les sorties:

color: blue
color: red

(l'ordre peut être aléatoire - c'est une carte) Cela peut être utile si vous connaissez l'élément de carte que vous souhaitez. Faites juste attention aux valeurs de falsification.


-1

J'utilisais une ancienne version 1.0.beta.6du guidon, je pense que quelque part entre 1.1 et 1.3, cette fonctionnalité a été ajoutée, donc la mise à jour vers 1.3.0 a résolu le problème, voici l'utilisation:

Usage:

{{#each object}}
  Key {{@key}} : Value {{this}}
{{/people}}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.