В усах, как получить индекс текущего раздела
Я использую ус и, используя данные
{ "names": [ {"name":"John"}, {"name":"Mary"} ] }
мой шаблон усы:
{{#names}}
{{name}}
{{/names}}
то, что я хочу быть в состоянии сделать это, чтобы получить индекс текущего числа в массив. Что-то вроде:
{{#names}}
{{name}} is {{index}}
{{/names}}
и пусть он распечатает
John is 1
Mary is 2
можно ли получить это с усами? или с рулями или другим расширением?
10 ответов:
Для справки, эта функция теперь встроена в руль, который имеет совместимость с усами.
использовать
{{@index}}
{{#names}} {{name}} is {{@index}} {{/names}}
Джон 0
Мэри - 1
вот как я это делаю в JavaScript:
var idx = 0; var data = { "names": [ {"name":"John"}, {"name":"Mary"} ], "idx": function() { return idx++; } }; var html = Mustache.render(template, data);
шаблон:
{{#names}} {{name}} is {{idx}} {{/names}}
в руле.js вы можете выполнить это с помощью вспомогательной функции. (На самом деле, одно из преимуществ, упомянутых о руле здесь http://yehudakatz.com/2010/09/09/announcing-handlebars-js/ это то, что вы можете использовать помощники вместо того, чтобы переписывать объекты перед вызовом шаблона.
Так, вы могли бы сделать это:
var nameIndex = 0; Handlebars.registerHelper('name_with_index', function() { nameIndex++; return this.name + " is " + nameIndex; })
и, то шаблон может быть таким:
{{#names}} <li>{{name_with_index}}</li> {{/names}}
ваши данные такие же, как и раньше, т. е.:
{ "names": [ {"name":"John"}, {"name":"Mary"} ] };
и вы получаете этот вывод:
<li>John is 1</li> <li>Mary is 2</li>
чтобы это действительно работало, nameIndex должен сбрасываться каждый раз, когда шаблон отображается, поэтому для этого у вас может быть помощник сброса в начале списка. Поэтому полный код выглядит так:
var data = { "names": [ {"name":"John"}, {"name":"Mary"} ] }; var templateSource = "<ul>{{reset_index}}{{#names}}<li>{{name_with_index}}</li>{{/names}}</ul>"; var template = Handlebars.compile(templateSource); var helpers = function() { var nameIndex = 0; Handlebars.registerHelper('name_with_index', function() { nameIndex++; return this.name + " is " + nameIndex; }); Handlebars.registerHelper('reset_index', function() { nameIndex = 0; }) }(); var htmlResult= template(data); $('#target').html(htmlResult); var htmlResult2= template(data); $('#target2').html(htmlResult2);
(это может правильно отобразить шаблон дважды.)
вы можете запустить следующий цикл в списке объектов.
данное решение имеет следующие преимущества:
- не изменяет данные модели
- индекс может быть получен несколько раз
код:
for( var i=0; i< the_list.length; i++) { the_list[i].idx = (function(in_i){return in_i+1;})(i); }
объяснение:
вместо имени переменной используется функция, поэтому данные не мутируют. Закрытие используется для возврата значения 'i' в то время функция создается в цикле вместо значения i в конце цикла.
лучший подход для усов будет использовать функцию, которая возвращает индекс с помощью
indexOf
:var data = { names: [ {"name":"John"}, {"name":"Mary"} ], index: function() { return data.names.indexOf(this); } }; var html = Mustache.render(template, data);
в вашем шаблоне:
{{#names}} {{name}} is {{index}} {{/names}}
недостаток в том, что это
index
функция имеет жестко закодированный массивdata.names
чтобы сделать его более динамичным, мы можем использовать другую функцию, как это:var data = { names: [ {"name":"John"}, {"name":"Mary"} ], index: function() { return function(array, render) { return data[array].indexOf(this); } } }; var html = Mustache.render(template, data);
использование в вашем шаблоне:
{{#names}} {{name}} is {{#index}}names{{/index}} {{/names}}
также небольшой недостаток заключается в том, что вы должны передать имя массива в функцию индекса в этом пример
names
,{{#index}}names{{/index}}
.
большой помощник здесь:
// {{#each_with_index records}} // <li class="legend_item{{index}}"><span></span>{{Name}}</li> // {{/each_with_index}} Handlebars.registerHelper("each_with_index", function(array, fn) { var buffer = ""; for (var i = 0, j = array.length; i < j; i++) { var item = array[i]; // stick an index property onto the item, starting with 1, may make configurable later item.index = i+1; // show the inside of the block buffer += fn(item); } // return the finished buffer return buffer; });
Источник:https://gist.github.com/1048968
Если вы можете управлять выводом строки JSON,то попробуйте это.
{ "names": [ {"name":"John", "index":"1"}, {"name":"Mary", "index":"2"} ] }
поэтому, когда вы делаете свою строку JSON, добавьте индекс в качестве другого свойства для каждого объекта.
мой основной вариант использования для этого была возможность устанавливать "активный" класс на предметы. Я возился с объединением помощника" equals "с помощником" index_for_each", но это было слишком сложно.
вместо этого я придумал следующий базовый "активный" помощник. Это очень специфично, но это такой общий случай использования для любого сценария меню / списка выбора:
использование:
<ul> {{{active 2}}} {{#each menuItem}} <li class="{{{active}}}">{{this}}</li> {{/each}} </div>
сделал бы 3-й пункт меню иметь "class= 'active'".
в помощник здесь (это версия CoffeeScript):
active = 0 cur = 0 handlebars.registerHelper 'active', (item, context) -> if arguments.length == 2 active = item cur = 0 '' else if cur++ == active 'active'
пока вы не путешествуете в более чем один массив, вы можете хранить индекс на помощнике и просто увеличивать его при изменении контекста. Я использую что-то похожее на следующее:
var data = { foo: [{a: 'a', 'b': 'a'}, {'a':'b', 'b':'b'}], i: function indexer() { indexer.i = indexer.i || 0; if (indexer.last !== this && indexer.last) { indexer.i++; } indexer.last = this; return String(indexer.i); } }; Mustache.render('{{#foo}}{{a}}{{i}}{{b}}{{i}}{{/foo}}', data);
(проверено в узле 4.4.7, усы 2.2.1.)
если вы хотите хороший чистый функциональный способ сделать это, что не включает в себя глобальные переменные или мутации самих объектов, используйте эту функцию;
var withIds = function(list, propertyName, firstIndex) { firstIndex |= 0; return list.map( (item, idx) => { var augmented = Object.create(item); augmented[propertyName] = idx + firstIndex; return augmented; }) };
использовать его, когда вы собираете свой вид;
var view = { peopleWithIds: withIds(people, 'id', 1) // add 'id' property to all people, starting at index 1 };
аккуратность этого подхода заключается в том, что он создает новый набор объектов "viewmodel", используя старый набор в качестве прототипов. Вы можете прочитать
person.id
так же, как вы бы читалиperson.firstName
. Однако, эта функция не изменяет ваши объекты people вообще, поэтому другой код (который мог бы полагаться на свойство ID, которого там нет) не будет затронут.алгоритм O (N), так красиво и быстро.