Manillar / bigote: ¿hay una forma integrada de recorrer las propiedades de un objeto?

216

Como dice el título de la pregunta, ¿hay alguna forma de bigote / manillar de recorrer las propiedades de un objeto ?

Entonces con

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

¿Puedo hacer algo en el motor de plantillas que sería equivalente a

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

?

Ben
fuente

Respuestas:

448

Soporte incorporado desde Handlebars 1.0rc1

El soporte para esta funcionalidad se ha agregado a Handlebars.js, por lo que ya no hay necesidad de ayudantes externos.

Cómo usarlo

Para matrices:

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

Para objetos:

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

Tenga en cuenta que solo hasOwnPropertyse enumerarán las propiedades que pasan la prueba.

Jon
fuente
2
@ Rafi: sin embargo, uno no puede tener mucho sentido sin conocer su estructura de datos.
Jon
3
@Rafi: ¿no te refieres a {{this.title}}?
nevyn
2
@qodeninja: Simple: de la misma manera que se refiere a los valores en los ejemplos anteriores, con {{#each this}}. Su elección de términos también es confusa (¿qué hace que un objeto sea de "nivel superior" y otro no? ¿Qué son exactamente las claves "predefinidas", etc.), por lo que es posible que desee volver a visitar estos conceptos.
Jon
1
si no se equivoca, solo con v1.1.0 está disponible, pero una gran respuesta, gracias.
Renars Sirotins
2
¿Cómo se hace esto solo para una lista blanca específica de propiedades?
Marco Prins
70

En realidad, es bastante fácil de implementar como ayudante:

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

Luego usándolo así:

{{#eachProperty object}}
    {{property}}: {{value}}<br/>
{{/eachProperty }}
Ben
fuente
2
Se ve bien, ¿necesita agregar una verificación hasOwnProperty dentro del bucle para que no esté iterando sobre las propiedades del prototipo?
monkeyboy
Gran solución @Ben. En caso de que alguien esté tratando de usar esto con Ember, vea mi respuesta a continuación para obtener la solución para que funcione.
pez volador
27

EDITAR: Los manillares ahora tienen una forma integrada de lograr esto; ver la respuesta seleccionada arriba. Cuando se trabaja con bigote simple, lo siguiente sigue siendo válido.

El bigote puede iterar sobre los elementos de una matriz. Por lo tanto, sugeriría crear un objeto de datos separado formateado de forma que Bigote pueda trabajar con:

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

Ahora, su plantilla de bigote sería algo así como:

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

Consulte la sección "Listas no vacías" aquí: https://github.com/janl/mustache.js

Amit
fuente
1
Terminé yendo con su sugerencia, ya que necesito pasar algunas propiedades secundarias adicionales de todos modos. ¡Gracias por la ayuda!
Ben
Muchas gracias, su idea me salvó otro día de buscar alternativas. Esta línea es la clave bigoteFormattedData = {'people': []};
Matt
¿Cómo haría esto con una matriz de objetos "o"?
red888
4

Esta es la respuesta de @ Ben actualizada para usar con Ember ... tenga en cuenta que debe usarla Ember.getporque el contexto se pasa como una Cadena.

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

Modelo:

{{#eachProperty object}}
  {{key}}: {{value}}<br/>
{{/eachProperty }}
pez volador
fuente
Gracias @flynfish. El contexto es una cadena en Ember ?? eso parece ... algo extraño.
Ben
Sí, no estoy muy seguro ya que soy nuevo en Ember y sigo tratando de encontrar el camino.
flynfish
1

La respuesta de @ Amit es buena porque funcionará tanto en bigote como en manillar.

En cuanto a las soluciones exclusivas para manillares, he visto algunas y me gusta el each_with_keybloqueador en https://gist.github.com/1371586 el mejor.

  • Le permite iterar sobre literales de objetos sin tener que reestructurarlos primero, y
  • Te da control sobre lo que llamas la variable clave. Con muchas otras soluciones, debe tener cuidado al usar claves de objeto con el nombre 'key', o 'property', etc.
mjumbewu
fuente
Buen hallazgo Solo una advertencia para otros lectores: el ayudante "key_value" en esta esencia tiene un error. Lea los comentarios sobre cómo solucionarlo.
sirentian
0

Gracias por la solución de Ben, mi caso de uso para mostrar solo campos particulares en orden

con objeto

Código:

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

Objeto de origen:

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

Modelo:

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

Salida:

locationDesc --- abc
description --- def
name --- ghi
vincentlcy
fuente
0

Esta es una función auxiliar para bigoteJS, sin formatear previamente los datos y en su lugar obtenerlos durante el 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'
        }
    }
};

Modelo:

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

Salidas:

color: blue
color: red

(el orden puede ser aleatorio, es un mapa) Esto podría ser útil si conoce el elemento del mapa que desea. Solo ten cuidado con los valores falsos.

Cuel
fuente
-1

Estaba usando una versión anterior 1.0.beta.6del manillar, creo que en algún lugar durante 1.1 - 1.3 se agregó esta funcionalidad, por lo que actualizar a 1.3.0 resolvió el problema, aquí está el uso:

Uso:

{{#each object}}
  Key {{@key}} : Value {{this}}
{{/people}}
AamirR
fuente