В Усы, Как получить индекс текущего раздела - PullRequest
55 голосов
/ 16 февраля 2011

Я использую Усы и использую данные

{ "names": [ {"name":"John"}, {"name":"Mary"} ] }

Мой шаблон усов:

{{#names}}
    {{name}}
{{/names}}

Что я хочу сделать, этополучить индекс текущего номера в массиве.Что-то вроде:

{{#names}}
    {{name}} is {{index}}
{{/names}}

и распечатать его

John is 1
Mary is 2

Возможно ли получить это с усами?или с рулем или другим расширением?

Ответы [ 12 ]

47 голосов
/ 18 апреля 2012

Вот как я делаю это в 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}}
30 голосов
/ 26 ноября 2012

Для справки, эта функциональность теперь встроена в руль, который совместим с усами.

Использование {{@index}}

{{#names}}
    {{name}} is {{@index}}
{{/names}}

Джон - 0

Мэри -1

13 голосов
/ 22 февраля 2011

В handlebars.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);

(Это может правильно отобразить шаблон дважды.)

7 голосов
/ 23 сентября 2012

Вы можете запустить следующий цикл в вашем списке объектов.

Это решение имеет следующие преимущества:

  • Не меняет данные модели
  • Доступ к индексу можно получить несколько раз

Код:

for( var i=0; i< the_list.length; i++) {
    the_list[i].idx = (function(in_i){return in_i+1;})(i);
}

Пояснение:

Вместо имени переменной используется функция, поэтому данные не видоизменяются. Замыкание используется для возврата значения 'i' в момент создания функции в цикле вместо значения i в конце цикла.

6 голосов
/ 26 октября 2014

Лучшим подходом для Усов было бы использование функции, которая получает индекс, используя 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}}.

4 голосов
/ 06 ноября 2011

Великий помощник здесь:

// {{#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

1 голос
/ 21 июля 2016

(проверено в узле 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), очень хороший и быстрый.

1 голос
/ 29 июня 2013

Пока вы не перемещаетесь в более чем один массив, вы можете хранить индекс на помощнике и просто увеличивать его при изменении контекста. Я использую что-то похожее на следующее:

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);
1 голос
/ 06 сентября 2012

Моим основным вариантом использования для этого была возможность помещать «активный» класс на предметы.Я возился с объединением помощника «равно» и помощника «index_for_each», но это было слишком сложно.

Вместо этого я придумал следующий базовый «активный» помощник.Это очень специфично, но это такой распространенный сценарий использования для любого сценария меню / списка выбора:

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

  <ul>
    {{{active 2}}}
    {{#each menuItem}}
      <li class="{{{active}}}">{{this}}</li>
    {{/each}}
  </div>

У третьего пункта меню будет "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'
1 голос
/ 16 февраля 2011

Если вы можете контролировать вывод строки JSON, попробуйте это.

{ "names": [ {"name":"John", "index":"1"}, {"name":"Mary", "index":"2"} ] }

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

...