Guiador / Bigode - Existe uma maneira integrada de percorrer as propriedades de um objeto?


216

Como o título da pergunta diz, existe uma maneira de bigode / guidão de percorrer as propriedades de um objeto ?

Então com

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

Posso então fazer algo no mecanismo de modelo que seria equivalente a

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

?

Respostas:


448

Suporte interno desde o guidão 1.0rc1

O suporte para essa funcionalidade foi adicionado ao Handlebars.js, portanto, não há mais necessidade de auxiliares externos.

Como usá-lo

Para matrizes:

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

Para objetos:

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

Observe que apenas as propriedades que passam no hasOwnPropertyteste serão enumeradas.


2
@ Rafi: não se pode entender muito isso sem conhecer sua estrutura de dados.
— 22413 Jon

3
@ Rafi: você não quis dizer {{this.title}}?
— Nevyn

2
@qodeninja: Simples: da mesma maneira que você se refere aos valores nos exemplos acima - com {{#each this}}. Sua escolha de termos também é confusa (o que torna um objeto "de nível superior" e outro não? O que são chaves "predefinidas" exatamente? Etc)); portanto, você pode revisitar esses conceitos.
— 11114 Jon

1
se não se enganar, apenas a v1.1.0 estará disponível, mas ótima resposta, obrigado.
— Renars Sirotins

2
Como você faz isso apenas para uma lista de permissões específica de propriedades?
— Marco Prins

70

Na verdade, é muito fácil de implementar como auxiliar:

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

Depois, use-o assim:

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

2
Parece bom, você precisa adicionar uma verificação hasOwnProperty dentro do loop para não iterar sobre as propriedades do protótipo?
— Monkeyboy

Ótima solução @Ben. Caso alguém esteja tentando usar isso com o Ember, veja minha resposta abaixo para a solução para fazê-lo funcionar.
— flynfish

27

EDIT: O guidão agora tem uma maneira interna de fazer isso; veja a resposta selecionada acima. Ao trabalhar com bigode comum, o seguinte ainda se aplica.

O bigode pode iterar sobre itens em uma matriz. Então, sugiro criar um objeto de dados separado, formatado de forma que o Bigode possa trabalhar:

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

Agora, seu modelo de bigode seria algo como:

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

Confira a seção "Listas não vazias" aqui: https://github.com/janl/mustache.js


1
Acabei seguindo a sua sugestão, pois preciso passar por algumas propriedades adicionais de qualquer maneira. Obrigado pela ajuda!
— Ben

Muito obrigado, sua ideia me salvou mais um dia de busca de alternativas. Esta linha é a chave mustacheFormattedData = {'people': []};
— Matt

Como você faria isso com uma matriz de objetos "o"?
— precisa saber é o seguinte

4

Esta é a resposta de @ Ben atualizada para uso com o Ember ... note que você deve usar Ember.getporque o contexto é passado como uma 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;
});

Modelo:

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

Obrigado @flynfish. contexto é uma string em Ember ?? isso parece .. um pouco estranho.
— Ben

Sim, eu não tenho muita certeza, pois sou novo em Ember e ainda estou tentando descobrir o caminho.
— flynfish

1

@ A resposta de Amit é boa porque funcionará tanto no bigode quanto no guidão.

Quanto às soluções exclusivas do guidão, já vi algumas e gosto do each_with_keyauxiliar de bloco em https://gist.github.com/1371586 da melhor maneira.

  • Ele permite iterar sobre literais de objetos sem precisar reestruturá-los primeiro e
  • Isso lhe dá controle sobre o que você chama de variável-chave. Com muitas outras soluções, você precisa ter cuidado ao usar chaves de objeto nomeadas 'key', ou 'property', etc.

Bom achado. Apenas um aviso para outros leitores: o ajudante "key_value" nesta essência tem um bug. Leia os comentários para saber como corrigi-lo.
— sirentian

0

Obrigado pela solução de Ben, meu caso de uso para exibir apenas campos específicos em ordem

com 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 origem:

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

Modelo:

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

Resultado:

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

0

Essa é uma função auxiliar do mustacheJS, sem pré-formatar os dados e obtê-los durante a renderização.

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

Saídas:

color: blue
color: red

(a ordem pode ser aleatória - é um mapa) Isso pode ser útil se você souber o elemento do mapa que deseja. Cuidado com os valores falsos.


-1

Eu estava usando a versão antiga 1.0.beta.6do guidão, acho que em algum lugar durante 1.1 - 1.3 essa funcionalidade foi adicionada, então a atualização para a 1.3.0 resolveu o problema, aqui está o uso:

Uso:

{{#each object}}
  Key {{@key}} : Value {{this}}
{{/people}}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.