Вывести меню из json дерева

Нужно вывести меню на странице из json дерева. Но совсем запутался, как отобразить субменю. Должно получиться так:

<li class="nav-item">
  <a class="nav-link" href="#">О клинике</a>
</li>
<li class="nav-item dropdown">
  <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
            Услуги <i class='bx bx-chevron-down'></i>
          </a>
  <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
    <li><a class="dropdown-item" href="#">Донорские программы</a></li>
    <li><a class="dropdown-item" href="#">Анализы</a></li>
  </ul>
</li>
<li class="nav-item">
  <a class="nav-link" href="#">Врачи</a>
</li>

Сам скрипт вот такой:

let data = [
  {
    "text": "О клинике",
    "href": "about",
    "icon": "",
    "target": "_self",
    "page": ""
  },
  {
    "text": "Услуги",
    "href": "",
    "icon": "",
    "target": "_self",
    "page": "",
    "children": [
      {
        "text": "Донорские программы",
        "href": "",
        "icon": "",
        "target": "_self",
        "page": ""
      },
      {
        "text": "Анализы",
        "href": "",
        "icon": "",
        "target": "_self",
        "page": ""
      },
    ]
  },
  {
    "text": "Врачи",
    "href": "",
    "icon": "",
    "target": "_self",
    "page": ""
  },

];
    
    function parseMenu(ul, menu) {
        for (var i=0;i<menu.length;i++) {
            var li=$(ul).append('<li class="nav-item"><a class="nav-link" href="'+menu[i].href+'">'+menu[i].text+'</a></li>');
            if (menu[i].children!=null) {
                var subul=$('<li class="nav-item dropdown"><ul></ul><li>');
                $(li).append(subul);
                parseMenu($(subul), menu[i].children);
            }
        }
    }
    
    var menu = $('.tree-navbar');
    parseMenu(menu, data);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>


<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
    <ul class="navbar-nav me-auto mb-2 mb-lg-0 tree-navbar">
  
    </ul>
    </div>
  </div>
</nav>


Ответы (1 шт):

Автор решения: SwaD

Вывести меню с подменю из массива объектов можно следующим способом:

function parseMenu(menu) {
  return menu.reduce((acc, item) => {
    let li = `<li class="nav-item"><a class="nav-link" href="${item.href}">${item.text}</a>`
    if (item.children) {
      li += `<ul className="dropdown-menu" aria-labelledby="navbarDropdown">`
      li += item.children.map(it => `<li><a className="dropdown-item" href="#">${it.text}</a></li>`).join();
      li += `</ul>`
    }
    li += `</li>`;
    return acc + li;
  }, '');
}

const data = [{
    "text": "О клинике",
    "href": "about",
    "icon": "",
    "target": "_self",
    "page": ""
  },
  {
    "text": "Услуги",
    "href": "",
    "icon": "",
    "target": "_self",
    "page": "",
    "children": [{
        "text": "Донорские программы",
        "href": "",
        "icon": "",
        "target": "_self",
        "page": ""
      },
      {
        "text": "Анализы",
        "href": "",
        "icon": "",
        "target": "_self",
        "page": ""
      },
    ]
  },
  {
    "text": "Врачи",
    "href": "",
    "icon": "",
    "target": "_self",
    "page": ""
  },

];

// js
const menu = document.querySelector('.tree-navbar');
menu.innerHTML = parseMenu(data);

// jQuery
//const menu = $('.tree-navbar');
//$(menu).append(parseMenu(data));

// jQueery one-line (Если элемент больше не используется в коде)
// $('.tree-navbar').append(parseMenu(data))
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="tree-navbar"></div>

Если в дальнейшем подменю будут содержать еще подменю, то надо будет задуматься над созданием рекурсивной функции. Сейчас в этом нет необходимости и подменю проще добавлять вложенным циклом.

→ Ссылка