Задать вопрос
@mihail9108
Программист-самоучка.

Как вывести многоуровневый список?

Пытаюсь решить задачу - вывести на страницу json в виде многоуровневого списка. Сам список успешно выводится на страницу, выглядит правильно. Проблема - такие данные как стулья, диваны, столы должны формироваться в одном подсписке (сейчас их 3), светильники, вентиляторы - также в одном подспике (сейчас 2).
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="js/main-test.js" defer></script>
    <script src="http://code.jquery.com/jquery-latest.min.js"></script>
    <title>Json</title>
</head>
<body>
<ul id="container"></ul>
</body>
</html>


console.clear();
let d = document, container = d.querySelector('#container'), arr = [], box = [], list = [];

// схораненный json ответ 'http://test1.web-gu.ru/'
let obj = [
    {id: '3', parent_id: '100', name: 'Диваны'},
    {id: '4', parent_id: '100', name: 'Столы'},
    {id: '5', parent_id: '2', name: 'Стул Сакура'},
    {id: '6', parent_id: '2', name: 'Стул Бистро'},
    {id: '7', parent_id: '2', name: 'Стул Лайт'},
    {id: '8', parent_id: '2', name: 'Стул Блюз'},
    {id: '9', parent_id: '4', name: 'Стол Византия'},
    {id: '10', parent_id: '4', name: 'Стол Прайм'},
    {id: '11', parent_id: '4', name: 'Стол Айсберг'},
    {id: '12', parent_id: '3', name: 'Диван София'},
    {id: '13', parent_id: '3', name: 'Диван Адам'},
    {id: '14', parent_id: '-1', name: 'Электроприборы'},
    {id: '15', parent_id: '14', name: 'Светильники'},
    {id: '2', parent_id: '100', name: 'Стулья'},
    {id: '16', parent_id: '14', name: 'Вентиляторы'},
    {id: '17', parent_id: '15', name: 'Светильник Луна'},
    {id: '18', parent_id: '15', name: 'Светильник Янтарь'},
    {id: '100', parent_id: '-1', name: 'Мебель'},
];
for(let i in obj) arr[obj[i].id] = {'parent_id':obj[i].parent_id, 'name':obj[i].name};


createTreeDom(arr);

let xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        let data = JSON.parse(this.responseText);
        JSON.stringify(data);
        console.log(data);
    }
};

function createTreeDom(data) {
    // super
    for(let x in data){
        if(typeof data[data[x].parent_id] == 'undefined'){
            let ul = d.createElement('ul'), li = d.createElement('li');
            li.innerHTML = data[x].name;
            container.appendChild(ul);
            ul.appendChild(li);
            box[x] = ul;
        }else{
            list[x] = {'parent_id':data[x].parent_id, 'name':data[x].name};
        }
    }
    data = [];
    arr = [];
    // category
    for(let x in list){
        if(typeof box[list[x].parent_id] != 'undefined'){
            let ul = d.createElement('ul'),  li = d.createElement('ul');
            li.innerHTML = list[x].name;
            box[list[x].parent_id].appendChild(li);
            li.appendChild(ul);
            data[x] = ul;
        }else{
            arr[x] = {'parent_id':list[x].parent_id, 'name':list[x].name};
        }
    }
    // items
    for(let x in arr){
        let li = d.createElement('li');
        li.innerHTML = list[x].name;
        data[arr[x].parent_id].appendChild(li);
    }
}
  • Вопрос задан
  • 1394 просмотра
Подписаться 1 Простой Комментировать
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
Сначала превращаем плоский массив во вложенный:

function createTreeData(data, idKey, parentKey) {
  const tree = Object.fromEntries(data.map(n => [ n[idKey], { ...n, children: [] } ]));

  return Object
    .values(tree)
    .filter(n => !(tree[n[parentKey]] && tree[n[parentKey]].children.push(n)));
}

Затем из вложенного массива можно собрать разметку:

const createTreeHTML = data =>
  Array.isArray(data) && data.length
    ? `<ul>${data.map(n => `
         <li>
           ${n.name}
           ${createTreeHTML(n.children)}
         </li>`).join('')}
       </ul>`
    : '';

Или создавать элементы напрямую:

const createTreeElement = data =>
  data instanceof Array && data.length
    ? data.reduce((ul, n) => (
        ul.append(document.createElement('li')),
        ul.lastChild.append(n.name, createTreeElement(n.children)),
        ul
      ), document.createElement('ul'))
    : '';

Вот так всё просто получается:

const treeData = createTreeData(obj, 'id', 'parent_id');

document.body.insertAdjacentHTML('beforeend', createTreeHTML(treeData));
document.body.append(createTreeElement(treeData));

Но вообще, можно ещё проще - без собирания вложенного массива:

function createTreeElements(arr, idKey, parentKey) {
  const tree = arr.reduce((acc, { [parentKey]: n }) => (
    acc[n] = acc[n] || document.createElement('ul'),
    acc
  ), {});

  arr.forEach(n => (
    tree[n[parentKey]].append(document.createElement('li')),
    tree[n[parentKey]].lastChild.append(n.name, tree[n[idKey]] || '')
  ));

  return Object.values(tree).filter(n => !n.parentNode);
}


document.body.append(...createTreeElements(obj, 'id', 'parent_id'));
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы