development

Mustache에서 현재 섹션의 색인을 얻는 방법

big-blog 2021. 1. 6. 20:44
반응형

Mustache에서 현재 섹션의 색인을 얻는 방법


내가 사용하고 콧수염을 하고 데이터를 사용하여

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

내 콧수염 템플릿은 다음과 같습니다.

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

내가 할 수 있기를 원하는 것은 배열에서 현재 숫자의 인덱스를 얻는 것입니다. 다음과 같은 것 :

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

그리고 그것을 인쇄하십시오

John is 1
Mary is 2

Mustache로 이것을 얻을 수 있습니까? 또는 핸들 바 또는 다른 확장으로?


참고로이 기능은 이제 Mustache와 호환되는 Handlebars에 내장되어 있습니다.

사용하다 {{@index}}

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

John은 0입니다.

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

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

(이렇게하면 템플릿을 두 번 올바르게 렌더링 할 수 있습니다.)


개체 목록에서 다음 루프를 실행할 수 있습니다.

이 솔루션에는 다음과 같은 장점이 있습니다.

  • 모델 데이터를 변경하지 않습니다.
  • 색인은 여러 번 액세스 할 수 있습니다.

암호:

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

설명:

변수 이름 대신 함수가 사용되므로 데이터가 변경되지 않습니다. Closure는 루프 끝의 i 값 대신 루프에서 함수가 생성 될 때 'i'값을 반환하는 데 사용됩니다.


Mustache에 대한 더 나은 접근 방식은 다음을 사용하여 색인을 가져 오는 함수를 사용하는 것입니다 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>

세 번째 메뉴 항목에 "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에서 테스트되었습니다.)

If you want a nice clean functional way to do it, that doesn't involve global variables or mutating the objects themselves, use this function;

var withIds = function(list, propertyName, firstIndex) {
    firstIndex |= 0;
    return list.map( (item, idx) => {
        var augmented = Object.create(item);
        augmented[propertyName] = idx + firstIndex;
        return augmented;
    })
};

Use it when you're assembling your view;

var view = {
    peopleWithIds: withIds(people, 'id', 1) // add 'id' property to all people, starting at index 1
};

The neat thing about this approach is that it creates a new set of 'viewmodel' objects, using the old set as prototypes. You can read the person.id just as you would read person.firstName. However, this function doesn't change your people objects at all, so other code (which might have relied on the ID property not being there) will not be affected.

Algorithm is O(N), so nice and fast.



Recommended Solution


My recommendation is to add an index key

let data = { "names": [ {"name":"John"}, 
{"name":"Mary"} ] };

// Add an index manually
data = {
  names: [
    { id: 0, name: "John" },
    { id: 1, name: "Mary" }
  ]
};

// Add an index with a loop
data = data.names
  .map(function (name, i) {
    name.id = i;
    return name;
  });

// Nested arrays with indices (parentId, childId)
data = {
  names: [{
    parentId: 0,
    name: "John",
    friends: [{
      childId: 0,
      name: "Mary"
    }]
  }]
};

Other proposed solutions are not as clean, and suffer from quite a few issues as detailed below.


Problems with proposed Mustache Index solutions


@Index

Mustache does not support @Index

IndexOf

This solution runs in O(n^2) time, and therefore it does not have the best performance. Also the index must be manually created for each list.

const data = {
  list: ['a', 'b', 'c'],
  listIndex: function () {
    return data.list.indexOf(this);
  }
};

Mustache.render('{{#list}}{{listIndex}}{{/list}}', data);

Global Variable

This solution runs in O(n) time, so better performance here, but also "pollutes the global space" (i.e. any properties added to the window object, do not get garbage collected until the browser window closes), and the index must be manually created for each list.

const data = {
  list: ['a', 'b', 'c'],
  listIndex: function () {
    return (++window.listIndex || (window.listIndex = 0));
  }
};

Mustache.render('{{#list}}{{listIndex}}{{/list}}', data);

Local Variable

This solution runs in O(n) time, does not "pollute the global space", and does not need to be manually created for each list. However, the solution is complex and does not work well with nested lists.

const data = {
  listA: ['a', 'b', 'c'],
  index: () => name => (++data[`${name}Index`] || (data[`${name}Index`] = 0))
};

Mustache.render('{{#listA}}{{#index}}listA{{/index}}{{/listA}}', data);

<script>var index = 1;</script>
{{#names}}
    {{name}} is <script>document.write(index++);</script>
{{/names}}

This works perfectly fine.

ReferenceURL : https://stackoverflow.com/questions/5021495/in-mustache-how-to-get-the-index-of-the-current-section

반응형