Convert JSON to a Multilevel Bulleted List Using JS

7.9k views Asked by At

Can some one help me make the following JSON data:

{
 "main": {
  "label":"Main",
  "url":"#main"
 },
 "project": {
  "label":"Project",
  "url":"#project"
 },
 "settings": {
  "label":"Settings",
  "url":"#settings",
  "subnav":[
  {
   "label":"Privacy",
   "url":"#privacy"
  },
  {
   "label":"Security",
   "url":"#security"
  },
  {
   "label":"Advanced",
   "url":"#advanced"
  }
  ]
 }
}

into the following bullets list using JS? Assuming you don't know what the first nodes are call labeled (e.g. "main", "project" <- these will be dynamically generated):

  • Main (#main)
  • Project (#project)
  • Settings (#settings)
    • Privacy (#privacy)
    • Security (#security)
    • Advanced (#advanced)

Thanks

2

There are 2 answers

0
littlegreen On

My code is on JSfiddle.

As JSON parser I used this one.

The main code is a recursive renderer of the parsed JSON:

function recursive_parse(result) {
    var html = '<ul>';
    for (var k in result) {
        html = html + '<li>' + result[k].label + ' (' + result[k].url + ')';
        html = html + recursive_parse(result[k].subnav);
        html = html + '</li>';
    }
    html = html + '</ul>';
    return html;
}

var result = json_parse($("div#test1111").html());
var html = recursive_parse(result);
$("div#test2222").html(html);
2
bobince On

Let's not use HTML string-hacking, shall we? That would break as soon as any of the data had characters like < or & in (or " in attribute values). Use DOM methods and you don't have to worry about character escaping:

function createNav(navs) {
    var ul= document.createElement('ul');
    for (name in navs) {
        var nav= navs[name];
        var a= document.createElement('a');
        a.href= nav.url;
        a.appendChild(document.createTextNode(nav.label));
        var li= document.createElement('li');
        li.id= 'nav-'+name;
        li.appendChild(a)
        if ('subnav' in nav)
            li.appendChild(createNav(nav.subnav));
        ul.appendChild(li);
    }
    return ul;
}

document.getElementById('navcontainer').appendChild(createNav(jsondata));

Most JS frameworks offer shortcuts to make this a bit less wordy. For example with jQuery:

function createNav(navs) {
    var ul= $('<ul>');
    for (name in navs) {
        var nav= navs[name];
        var li= $('<li>', {id: name});
        li.append($('<a>', {href: nav.url, text: nav.label}));
        if ('subnav' in nav)
            li.append(createNav(nav.subnav));
        ul.append(li);
    }
}

$('#navcontainer').append(createNav(jsondata));

Note that either way, you're using an Object literal which means you get no control over the order the list of navs comes out. You have no guarantee that main will be above project. If you want a defined order, you will have to have the returned JSON data be an array.