Рули / Усы - есть ли встроенный способ перебирать свойства объекта?

216

Как гласит заголовок вопроса, есть ли усы / руль способ прохождения свойств объекта ?

Так с

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

Могу ли я затем сделать что-то в движке шаблонов, что будет эквивалентно

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

?

Бен
источник

Ответы:

448

Встроенная поддержка начиная с Handlebars 1.0rc1

Поддержка этой функциональности была добавлена в Handlebars.js, поэтому больше нет необходимости во внешних помощниках.

Как это использовать

Для массивов:

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

Для объектов:

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

Обратите внимание, что hasOwnPropertyбудут перечислены только свойства, прошедшие тест.

Джон
источник
2
@Rafi: никто не может понять это, не зная структуры данных.
Джон
3
@Rafi: ты не имеешь в виду {{this.title}}?
Невин
2
@qodeninja: Simple: так же, как вы ссылаетесь на значения в примерах выше - with {{#each this}}. Ваш выбор терминов также сбивает с толку (что делает один объект «верхним уровнем», а другой - нет, а что такое «предварительно определенные ключи» и т. Д.), Поэтому вы можете захотеть вернуться к этим понятиям.
Джон,
1
если не ошибаюсь, то только с v1.1.0 это доступно, но отличный ответ спасибо.
Ренарс Сиротинс
2
Как вы делаете это только для определенного белого списка свойств?
Марко Принс
70

На самом деле это довольно легко реализовать в качестве помощника:

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

Тогда используя это так:

{{#eachProperty object}}
    {{property}}: {{value}}<br/>
{{/eachProperty }}
Бен
источник
2
Выглядит хорошо, вам нужно добавить проверку hasOwnProperty внутри цикла, чтобы не перебирать свойства прототипа?
Обезьяна
Отличное решение @Ben. В случае, если кто-то пытается использовать это с Ember, см. Мой ответ ниже для решения, чтобы заставить это работать.
flynfish
27

РЕДАКТИРОВАТЬ: у руля теперь есть встроенный способ сделать это; см выбранный ответ выше. При работе с простыми усами, все еще действует нижеследующее.

Усы могут перебирать элементы в массиве. Поэтому я бы предложил создать отдельный объект данных, отформатированный таким образом, чтобы усы могли работать:

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

Теперь ваш шаблон усов будет выглядеть примерно так:

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

Проверьте раздел «Непустые списки» здесь: https://github.com/janl/mustache.js

Amit
источник
1
Закончилось тем, что я пошел с вашим предложением, так как мне все равно нужно передать некоторые дополнительные свойства. Спасибо за помощь!
Бен
Большое спасибо, ваша идея спасла меня еще один день поиска альтернатив. Эта строка является ключом mustacheFormattedData = {'people': []};
Мэтт
Как бы вы сделали это с массивом объектов «о»?
red888
4

Это ответ @ Ben, обновленный для использования с Ember ... обратите внимание, что вы должны использовать, Ember.getпотому что контекст передается как строка.

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

Шаблон:

{{#eachProperty object}}
  {{key}}: {{value}}<br/>
{{/eachProperty }}
flynfish
источник
Спасибо @flynfish. контекст это строка в Ember ?? это кажется .. несколько странным.
Бен
Да, я не совсем уверен, так как я новичок в Эмбер и все еще пытаюсь найти способ обойти это.
летучая рыба
1

Ответ @ Амит хорош, потому что он будет работать как на усы, так и на руле.

Что касается решений, предназначенных только для Handlebars, я видел несколько из них, и мне больше всего нравится each_with_keyпомощник по адресу https://gist.github.com/1371586 .

  • Это позволяет вам перебирать литералы объекта без необходимости сначала их реструктурировать, и
  • Это дает вам контроль над тем, что вы называете ключевой переменной. Во многих других решениях вы должны быть осторожны при использовании именованных ключей объектов 'key', или 'property'и т. Д.
mjumbewu
источник
Хорошая находка. Просто предупреждение для других читателей: у помощника "key_value" в этой сущности есть ошибка. Прочитайте комментарии о том, как это исправить.
сирена
0

Спасибо за решение Бена, мой вариант использования для отображения только определенных полей в порядке

с объектом

Код:

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

Исходный объект:

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

Шаблон:

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

Вывод:

locationDesc --- abc
description --- def
name --- ghi
vincentlcy
источник
0

Это вспомогательная функция для mustacheJS, без предварительного форматирования данных и получения их во время рендеринга.

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

Шаблон:

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

Выходы:

color: blue
color: red

(порядок может быть случайным - это карта). Это может быть полезно, если вы знаете нужный элемент карты. Просто следите за ложными ценностями.

Cuel
источник
-1

Я использовал старую версию 1.0.beta.6руля, я думаю, что где-то во время 1.1 - 1.3 эта функциональность была добавлена, поэтому обновление до 1.3.0 решило проблему, вот использование:

Использование:

{{#each object}}
  Key {{@key}} : Value {{this}}
{{/people}}
AamirR
источник