views:

66

answers:

3

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

A: 

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);
littlegreen
A: 

Unomi, here's what I have:

var m1 = {
  "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"
      }
    ]
  }
};

var renderItem = function(item){
  return "<li><a href='"+item.url+"'>"+item.label+"</a></li>"; 
};

var renderList = function(list){
  var renderedList = "<ul>";
  var renderedItem = "";
  for (item in list){
    renderedItem = renderItem(item);
    if(item.subnav){
      renderedItem.replace("</li>", renderList(item.subnav) +"</li>");
    }
    renderedList += renderedItem;
  }
  return renderedList + "</ul>";
}

var lc = document.getElementById("container");
lc.innerHTML = renderList(m1);

But it only renders the following:

  • undefined
  • undefined
  • undefined
Tony2K
+2  A: 

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.

bobince
Thanks, the first version of the code works but the jQuery version doesn't.
Tony2K