Ractive.js Вложенный список из одного массива элементов с родительской связью

У вас есть список элементов со свойствами id, parentid и message. parentid ссылается на другой элемент в том же списке. Количество вложенных уровней не ограничено. Как бы вы это реализовали?

Другими словами, как это принять:

var data = [
    {
        id: 1,
        parentid: 0,
        message: "I'm 1, and I have no parent."
    }, {
        id: 2,
        parentid: 1,
        message: "I'm 2, and 1 is my parent."
    }, {
        id: 3,
        parentid: 1,
        message: "I'm 3, and 1 is my parent."
    }, {
        id: 4,
        parentid: 0,
        message: "I'm 4, and I have no parent."
    }, {
        id: 5,
        parentid: 1,
        message: "I'm 5, and 2 is my parent."
    }
];

И превратите это в это:

<ul>
    <li>
        I'm 1, and I have no parent.
        <ul>
            <li>
                I'm 2, and 1 is my parent.
                <ul>
                    <li>
                        I'm 5, and 2 is my parent.
                    </li>
                </ul>
            </li>
            <li>
                I'm 3, and 1 is my parent.
            </li>
        </ul>
    </li>
    <li>
        I'm 4, and I have no parent.
    </li>
</ul>

Есть ли хороший и быстрый способ сделать это в шаблоне? Без перебора всего массива, создания нового и его рендеринга?

И даже чем, какова лучшая реализация шаблона, который рекурсивно рендерится до тех пор, пока ничего не останется?


person ythis    schedule 26.03.2014    source источник
comment
Предполагая, что последний элемент данных id: 5 должен быть parentid: 2, а не parentid: 1   -  person martypdx    schedule 28.03.2014
comment
Хотел это исправить, но Редактирование должно быть не менее 6 символов :/   -  person ythis    schedule 28.03.2014


Ответы (1)


С помощью ractive.js вы можете использовать javascript для фильтрации массива с помощью вспомогательной функции частичного выражения и выражения (см. http://jsfiddle.net/pUf5P/1/ для полного примера)

Шаблон:

{{# { index: 0 } }}
{{>lister}}
{{/ }}

<!-- {{>lister}} -->
  <ul>
  {{# filter(list, .index) }}
    <li>{{message}}
      {{# { index: id } }}
         {{>lister}}
      {{/ }}
   </li>
  {{/ }}
  </ul>
<!-- {{/lister}} -->

Настраивать:

new Ractive({
    el: 'body',
    template: '#template',
    data: { 
        list: data,
        filter: function(list, parent){
            return list.filter(function(item){
                return item.parentid === parent
            })
        }      
    }
})

Или для решения с чистым шаблоном (см. http://jsfiddle.net/pUf5P/2/), ты можешь сделать:

{{# { index: 0 } }}
{{>lister}}
{{/ }}

<!-- {{>lister}} -->
  <ul>
    {{#list}}
    {{# .parentid === index}}
    <li>{{message}} 
      {{# { index: .id } }}  
        {{>lister}}
      {{/ }}   
    </li>
    {{ /}}
  {{/list }}
  </ul>
<!-- {{/lister}} -->

ОБНОВЛЕНИЕ: я знаю, что вы хотели сделать это «без перебора всего массива, создавая новый», но понимаете, что вы перебираете весь массив на каждом уровне, чтобы найти совпадающие дочерние элементы. Вам не нужно создавать иерархическую структуру, просто группируйте элементы на основе родительского идентификатора (см. http://jsfiddle.net/pUf5P/3/):

var byParent = {}
data.forEach(function(item){
    if(!byParent[item.parentid]){ byParent[item.parentid] = [] }
    byParent[item.parentid].push(item)
})

Затем используйте вариант приведенной выше стратегии шаблона:

{{# { index: 0 } }}
{{>lister}}
{{/ }}

<!-- {{>lister}} -->
  <ul> 
    {{# { list: byParent[index]} }}
      {{#list}}
      <li> {{(.message)}}
        {{# { index: .id } }}
        {{>lister}}
        {{/ }}            
      </li>
      {{/list}}
    {{/ }}

  </ul>
<!-- {{/lister}} -->
person martypdx    schedule 27.03.2014
comment
Ага. Выполнение одного цикла для создания ведра намного быстрее, чем чистый шаблон или решение для фильтрации. Не знаю, чего еще я ожидал:/Спасибо за ответ :) - person ythis; 28.03.2014