remis4
remis4

Reputation: 35

Creating nested lists using jQuery

Ive tried a lot of the answers to creating nested ul/li, but cant seem to get create one. Im very new to js.

the data is grabbed after the page loads, and comes in a format like this

data = { 
  "key1": ["value1", value2", "value3"],
  "key2": ["value4", "value5", "value6"],
  "key2": ["value7"]
}

As a bonus, I was hoping to click on a key and drop down (expand) to show the values. But ive failed to get the data to load in the structure below. There can be any number of keys, with values(lists) of any length. also, the keys can be named anything.

<ul>
  <li>
    key1
    <ul>
      <li>value1</li>
      <li>value2</li>
      <li>value3</li>
    </ul>
  </li>
  <li>
    key2
    <ul>
      <li>value4</li>
      <li>value5</li>
      <li>value6</li>
    </ul>
  </li>
  <li>
    key3
    <ul>
      <li>value7</li>
    </ul>
  </li>
</ul>

i updated adding the jquery code ive been attempting. I did not include it because ive tried many variants to get the data in the nested structure above and am probably doing it wrong.

jQuery(document).ready(function($) {

$.get('url', function(data){

            var $ul = $('<ul></ul>');

            function getList(item, $list) {

                $.each(item, function (key, value) {
                    var $li = $('<li />');
                    $li.append($('<a href="#">' + key + '</a>'));

                    var $subul = $("<ul/>");

                    $.each(value, function(i) {
                        var subli = $('<li/>')
                        .text(value[i])
                        .appendTo(subli);
                    });
                    $subul.append(subli);


                    $li.append($subul)

                });
            }
            getList(data, $ul);
            $ul.appendTo("div_containing_ul");
    });});

Upvotes: 1

Views: 3382

Answers (3)

Florimond
Florimond

Reputation: 341

A short recursive version giving good results:

function buildList(data) {
    var $ul = $('<ul></ul>');
    for (const key in data) {
        var $child = $('<li></li>');
        $ul.append($child)
        if (typeof data[key] === 'object') {
            $child.text = $child.text(key);
            $child.append(buildList(data[key]));
        } else {
            $child.text = $child.text(key + ' : ' + data[key]);
        }
    }
    return $ul;
}

I feed my function with an array of objects containing a timestamp, a Partner object, and the Partner object containing a Company object; the result looks like this:

0
    timestamp : 1587732029600
    partner
        id : 0
        name : Name1
        email : [email protected]
        company
            id : 0
            name : SomeCompany1
1
    timestamp : 1587732029600
    partner
        id : 1
        name : Name2
        email : [email protected]
        company
            id : 1
            name : SomeCompany2

Upvotes: 1

DarkMukke
DarkMukke

Reputation: 2489

The problem is recursion. You don't know if that data will always be like that, if the nested levels will only be ever 2 levels deep.

I rewrote your example with recursion that takes in account an endless of levels of menus.

jQuery(document).ready(function ($) {


    function caller(data) {
        var $ul = $('<ul></ul>');
        recursiveCaller(data, $ul);
        return $ul;
    }

    function recursiveCaller(subdata, $parent) {
        if( typeof subdata === 'object' ) {
            for(var key in subdata) {
                $parent.text(key)
                var $sublist =  $('<ul></ul>');
                recursiveCaller(subdata[key], $sublist);
            }
        } else {
            var $child = $('<li></li>');
            $child.text(subdata)
            $parent.append($child);
        }
    }

    $.get('url', function () {
        var $menu = caller(data);
        $('#div_containing_ul').append($menu);
    });
});

This could easily deal with a structure like

var data = {
    'key1': ['val1', 'val2', 'val3'],
    'key2': [
        {'key2': ['val4', 'val5', 'val6']},
        'val5',
        'val6'],
    'key3': [
        {
            'key2':
                {
                    'key2': [
                        'val4',
                        {
                            'key2': ['val4', 'val5', 'val6']
                        },
                        'val6'],
                    0: 'val5',
                    1: 'val6'
                }
        }]
};

Good luck

Upvotes: 1

Gabriele Petrioli
Gabriele Petrioli

Reputation: 196002

An error and a missing append.

The .appendTo(subli); should really be .appendTo($subul); and at the end of the function you need to add the $li to the $list.

data = {
  "key1": ["value1", "value2", "value3"],
  "key2": ["value4", "value5", "value6"],
  "key3": ["value7"]
}

jQuery(document).ready(function($) {

  var $ul = $('<ul></ul>');

  function getList(item, $list) {

    $.each(item, function(key, value) {
      var $li = $('<li />');
      $li.append($('<a href="#">' + key + '</a>'));

      var $subul = $("<ul/>");

      $.each(value, function(i) {
        var subli = $('<li/>')
          .text(value[i])
          .appendTo($subul); // you need to append it to the $subul not the $subli
      });


      $li.append($subul).appendTo($list); // you need to append the $li to the $list

    });
  }
  getList(data, $ul);
  $ul.appendTo("#div_containing_ul");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="div_containing_ul"></div>

Upvotes: 1

Related Questions