Using jQuery to generate nested lists

I have attempted various solutions for creating nested ul/li elements without success. I am a beginner in JavaScript and struggling with this task.

The data is retrieved after the page has loaded, and it looks like this:

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

Additionally, I would like to implement a feature where clicking on a key will expand to display its corresponding values. However, I have been unable to structure the data as shown below. The number of keys and their values can vary greatly, so flexibility is important.

<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>

Below is the jQuery code snippet that I have tried implementing. I have omitted it here as my attempts to achieve the desired nested structure have been unsuccessful.

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");
    });});

Answer №1

An issue with appending and a crucial step missing.

The snippet .appendTo(subli); needs to be corrected to .appendTo($subul);, and don't forget to add the $li to the $list at the end of the function.

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); // make sure to append it to $subul

         });
       
       $li.append($subul).appendTo($list); // remember to include $li in $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>

Answer №2

The challenge lies in the concept of recursion. It's uncertain whether the data will always maintain its current structure, or if the nested levels will only ever reach a depth of two.

I've revised your code with recursion that can handle an endless number of menu levels.

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 approach can easily accommodate 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'
                }
        }]
};

Best of luck!

Answer №3

A concise recursive solution that yields accurate outcomes:

function generateList(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(generateList(data[key]));
        } else {
            $child.text = $child.text(key + ' : ' + data[key]);
        }
    }
    return $ul;
}

I utilize my function with an array of objects that include a timestamp, a Partner object, and the Partner object containing a Company object; the output is structured as follows:

0
    timestamp : 1587732029600
    partner
        id : 0
        name : Name1
        email : <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="553415377b363a38">[email protected]</a>
        company
            id : 0
            name : SomeCompany1
1
    timestamp : 1587732029600
    partner
        id : 1
        name : Name2
        email : <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3d5e7d59135e5250">[email protected]</a>
        company
            id : 1
            name : SomeCompany2

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

`Why is the color of the <select> element not changing in Firefox?`

I seem to be facing some difficulty replicating this issue accurately. However, I do have a jsfiddle link where the selected text color does not match the selected option text. http://jsfiddle.net/kralco626/9xJvF/8/ (similar to: seting <select> col ...

The Data Table experiences intermittent hanging issues (Table is empty) when sorting or loading data with Knockout binding

While working on a project, I encountered an issue with binding data to a table using Knockout JS and the JQuery/Bootstrap based; Data Table API. The problem was that the table would become unresponsive at times when sorted or loaded, without any errors be ...

The value of the innermost dropdown in the AngularJS Cascading dropdown is not being retrieved when it is selected

CSS <div ng-controller="DynamicCtrl"> <h1>Dynamic - Focused</h1> <p>This method works well when data is constantly changing</p> <div> Category: <select id="category" ng-model="items" ng-options="category ...

Whenever I click on a button, I want to modify the background color of my react-modal

Having an array of images with clickable overlays and a modal that changes the background color based on the overlay name when clicked is the goal. However, passing this value as a prop proves challenging since the images are generated through a function a ...

How can I easily add both horizontal and vertical arrows to components in React?

Creating a horizontal line is as simple as using the following code: <hr style={{ width: "80%", border: "1px solid black" }} /> You can customize the width, length, and other properties as needed. If you want to display an arrow ...

Efficiently Updating Multiple Highcharts Charts Using a Single Function

I have 4 different charts displayed on this page. <div id="section"> <div id="all" style="min-width: 400px; height: 400px; margin: 0 auto"></div> <div id="top10" style="min-width: 400px; height: 400px; margin: 0 auto">< ...

Turn off hover opacity effect for a specific image

Currently, I've implemented a hover opacity effect on my images using the following CSS: img { opacity: 1.0; filter: alpha(opacity=1.0); } img:hover { opacity: 0.6; filter: alpha(opacity=0.6); } However, I now have a specific image for whi ...

Discovering a specific property of an object within an array using Typescript

My task involves retrieving an employer's ID based on their name from a list of employers. The function below is used to fetch the list of employers from another API. getEmployers(): void { this.employersService.getEmployers().subscribe((employer ...

What is the best way to simulate an unexported function in Javascript jest environments?

Testing a module in my vuejs project is what I'm currently focusing on. import { getBaseUrl } from "@/application/api/baseUrl"; export default ( uri: string, requestBody: Record<string, string | number> ): void => { let form ...

Contrasting border with border-style

To eliminate all borders from my primefaces panelgrid component, I employ the following techniques: First method: .table, table td { border-style: hidden !important; } Second method: .table, table tr, table td { border: none !important; } Can ...

Unable to adjust the text color to white

As someone who is new to Typescript, I'm facing a challenge in changing the text color to white and struggling to find a solution. I'm hoping that someone can guide me in the right direction as I've tried multiple approaches without success ...

Adjusting the height of the navbar items to align with the size of the

In the bootstrap navbar below, I am trying to enlarge the search field to be large using 'input-lg', but this causes the other items in the navbar not to vertically center correctly. How can I align the other items in the navbar with the large in ...

What is causing the QJsonValue(undefined) to be returned?

After sending a request to the API for bid price, I am receiving an undefined QJsonValue and unable to display it later. Can anyone help me pinpoint where I might be going wrong? { QApplication a(argc, argv); MainWindow w; w.show(); QNetwor ...

Having issues with mouse hover not functioning on button in internet explorer 8?

Currently, I am working with asp.net mvc4 and encountering an issue where the button's color does not change when hovered over. The default blue focus always remains on the button. Can someone assist me in resolving this problem? I am using Internet E ...

"Autocomplete disable" feature malfunctioning on the final input field of all web pages

I'm dealing with a web application that has a login page. The username and password fields have the autocomplete attribute set to "off," as well as other variations like nope, new-password etc. However, it's still not working in Chrome version 62 ...

PugJS is failing to properly interpolate numbers from the JSON file

My goal is to display a list of interfaces retrieved from my router API, which is in JSON format. However, when using Pug, only the strings are being rendered and not the numbers. Here is the output (it displays correctly in HTML): em1 192.168.0.0/24 Addr ...

Utilizing multiple materials with a single mesh in three.js: A comprehensive guide

I am facing a major issue with three.js: My goal is to create a simple cube with different colors on each face. I attempted to achieve this using the following code snippet: // set the scene size var WIDTH = jQuery('#showcase').width() - 20 ...

Achieving vertical center alignment for the label and btn-group in Bootstrap

Is it possible to align other elements with the Bootstrap btn-group? <div class="btn-toolbar text-center"> <div class="pull-left"> <span class="glyphicon glyphicon-envelope " style="font-size:1.5em;"></span> < ...

A guide on organizing nested object data in react-native

{ "crocodile":{ "age_in_years":"20", "name":"snapjaw", "country":"australia" }, "jaguar":{ "age_in_years":"8", "name&q ...

Eliminate the chosen and marked items from a list - Angular 2+/ Ionic 2

Currently, I have a checkbox list on my page. Whenever a user selects the "Save" button, the checked items should be removed from the list and moved to the saved tab that is also displayed. While I have successfully implemented the functionality for removi ...