skip to Main Content

I have the following code below and trying to find a way to generate <ul> and <li> to output an unordered list via Javascript.

Question(s):

  1. How can I parse the following array to generate a nested unordered list html?
  2. If I were to use recursion, how would I recursively iterate through all nested children to print a nested unordered list?

What I tried that didn’t work

const data = [
    {
        name: '125313-7j',
    },
    {
        name: '584996-s7',
        _children: [
            {
                name: '747773-jw',
            },
            {
                name: '377526-zg',
                _children: [
                    {
                        name: '955330-wp',
                    },
                    {
                        name: '343693-9x',
                    },
                ],
            },
            {
                name: '638483-y2'
            },
        ],
    },
    {
        name: '306979-mx'
    },
    {
        name: '066195-o1',
        _children: [],
    },
];

$(function() {
let innerHtml = '<ul>';
data.forEach( item => {
  innerHTML += '<li>' + '<div>' + item.name + '</div>';
    if(item._children) {
      // ***ISSUE***  this doesn't print all the children so i cannot recursively get all the children
       console.log('children', item._children);
    }
});

innerHtml += '</ul>';
});

Expected output

<ul>
  <li> <div>Name1</div>
     <ul>
        <li><div>Name2</div>
         .... continue the next unordered list until all children have been displayed ...
      </ul>
   </li>
</ul>

2

Answers


  1. For your requirement, the recursive solution seems more intuitive to me. Let me share my insights for approaching this:

    # Pseudocode
    
    # generateList(items)
    #   1. init: html<String> with opening "<ul>" tag. 
    #            Can also use array. See References section
    
    #   2. for item in items
    #       2.1. html += "<li><div>", item.name, "</div>"
    #       2.2. if item has _children and the length of _children is greater than 0
    #            2.2.1. html += result of calling generateNestedList recursively with item._children
    #       2.3. html += closing "<li>"
    
    #   3. html += closing "</ul>"
    
    #   4. return html.
    # end function
    
    const data = [{
        name: '125313-7j',
      },
      {
        name: '584996-s7',
        _children: [{
            name: '747773-jw',
          },
          {
            name: '377526-zg',
            _children: [{
                name: '955330-wp',
              },
              {
                name: '343693-9x',
              },
            ],
          },
          {
            name: '638483-y2'
          },
        ],
      },
      {
        name: '306979-mx'
      },
      {
        name: '066195-o1',
        _children: [],
      },
    ];
    
    function generateList(items) {
      let html = '<ul>';
    
      items.forEach((item) => {
        html += '<li><div>' + item.name + '</div>';
        if (item._children?.length > 0) {
          html += generateList(item._children);
        }
        html += '</li>';
      });
    
      html += '</ul>';
      return html;
    }
    
    const innerHtml = generateList(data);
    // console.log(innerHtml);
    document.getElementById("list-container").innerHTML = innerHtml;
    <div id="list-container"></div>

    References:

    1. Array Join vs String Concat
    2. Optional Chaining(?.)
    Login or Signup to reply.
  2. As you seem to be using jQuery, here is a solution using jQuery style, producing the object structure, ready to inject in the HTML document:

    function createHtml(data) {
        return $("<ul>").append(
            (data ?? []).map(({ name, _children }) =>
                $("<li>").append(
                    $("<div>").text(name),
                    data?.length ? createHtml(_children) : []
                )
            )
        );
    }
    
    const data = [{name: '125313-7j',},{name: '584996-s7',_children: [{name: '747773-jw',},{name: '377526-zg',_children: [{name: '955330-wp',},{name: '343693-9x',},],},{name: '638483-y2'},],},{name: '306979-mx'},{name: '066195-o1',_children: [],},];
    const $ul = createHtml(data);
    $("#container").append($ul);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    
    <div id="container"></div>

    An advantage of setting the text with text(), is that you’ll not have issues if the item’s name has character sequences that could be misinterpreted as HTML, such as < or & in combination with other characters.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search