1

I have the following Json file and I am trying to iterate through everything however only 1 item from the nested array is showing up. Not sure what I am doing wrong here.

JSON:

{
   "items":[
      {
         "label":"red",
         "url":"red",
         "items":[

         ]
      },
      {
         "label":"blue",
         "url":"#/blue",
         "items":[
            {
               "label":"green",
               "url":"#/green"
            },
            {
               "label":"yellow",
               "url":"#/yellow"
            },
            {
               "label":"pink",
               "url":"#/pink"
            }
         ]
      },......

JS:

var d = document, 
        main = d.getElementsByTagName('nav')[ 0 ],
        ul = d.createElement( 'ul' ),
        i;

        main.appendChild( ul );

        axios.get('../data/colors.json')
        .then(function (response) {
            console.log(response.data.items);

            for( var i in response.data.items ){
                var li = d.createElement( 'li' ); 
                if(response.data.items[i].items.length){
                    li.innerHTML = "<a class='meta'>" + response.data.items[i].label + "<div>" + response.data.items[i].items[i].label + "</div>" + "</a>"; // create a new li element
                }
                else {
                    li.innerHTML = "<a class='meta'>" + response.data.items[i].label + "</a>"; // create a new li element
                }
                ul.appendChild( li );// every time append a new item

            }

        })
        .catch(function (error) {
            console.log(error);
        });

Desired output:

<ul>
<li>red<li>
<li>blue
  <div>green </div>
  <div>yellow </div>
  <div>pink</div>
</li>
</ul>

6
  • for( var i in response.data.items ){ - don't use for..in on an array, use a regular for loop - for..in is for iterating the properties of an object. Commented Jun 22, 2018 at 19:32
  • 1
    Or use the new for ... of. Commented Jun 22, 2018 at 19:33
  • What is the result you're looking for? Commented Jun 22, 2018 at 19:35
  • Just updated with desired result Commented Jun 22, 2018 at 19:40
  • @user992731 - Please try my suggestion - a regular for loop will solve your problems Commented Jun 22, 2018 at 19:43

5 Answers 5

3

You'll want to iterate/loop over the nested items, which you aren't doing. Basically add another loop for the 2nd level of items.

Here's a cleaned up version: http://jsfiddle.net/DennisRas/zyn52p8v/
Note: I've removed the .axios module to show what's important.

const data = {
   "items":[
      {
         "label":"red",
         "url":"red",
         "items":[

         ]
      },
      {
         "label":"blue",
         "url":"#/blue",
         "items":[
            {
               "label":"green",
               "url":"#/green"
            },
            {
               "label":"yellow",
               "url":"#/yellow"
            },
            {
               "label":"pink",
               "url":"#/pink"
            }
         ]
      },
      {
         "label":"blue",
         "url":"#/blue",
         "items":[
            {
               "label":"green",
               "url":"#/green"
            },
            {
               "label":"yellow",
               "url":"#/yellow"
            },
            {
               "label":"pink",
               "url":"#/pink"
            }
         ]
      },
      {
         "label":"blue",
         "url":"#/blue",
         "items":[
            {
               "label":"green",
               "url":"#/green"
            },
            {
               "label":"yellow",
               "url":"#/yellow"
            },
            {
               "label":"pink",
               "url":"#/pink"
            }
         ]
      }
    ]
};

const nav = document.querySelector('nav');
const ul = document.createElement( 'ul' );

nav.appendChild(ul);

data.items.forEach(function(item) {
  const li = document.createElement('li');
  let html = "<a class='meta'>" + item.label;

  if (item.items && item.items.length) {
    item.items.forEach(function(subitem) {
        html += "<div>" + subitem.label + "</div>";
    });
  }

  html += "</a>";

  li.innerHTML = html;
  ul.appendChild(li);// every time append a new item
});

console.log(data.items);
Sign up to request clarification or add additional context in comments.

Comments

1

Here's how you can do it -

var data = {
  "items": [{
      "label": "red",
      "url": "red",
      "items": [

      ]
    },
    {
      "label": "blue",
      "url": "#/blue",
      "items": [{
          "label": "green",
          "url": "#/green"
        },
        {
          "label": "yellow",
          "url": "#/yellow"
        },
        {
          "label": "pink",
          "url": "#/pink"
        }
      ]
    }
  ]
}

var createList = function(response) {
  var d = document,
    main = d.getElementById('list'),
    ul = d.createElement('ul'),
    i;

  main.appendChild(ul);

  //console.log(response.data.items);

  for (var i in response.data.items) {
    var li = d.createElement('li');
    if (response.data.items[i].items.length) {
      li.innerHTML = "<a class='meta'>" + response.data.items[i].label + "</a>"; // create a new li element
      ul.appendChild(li); // every time append a new item
      var innerul = d.createElement('ul');
      for (var j in response.data.items[i].items) {
        var innerli = d.createElement('li');
        innerli.innerHTML = "<div>" + response.data.items[i].items[j].label + "</div>"; // create a new li element
        innerul.appendChild(innerli);

      }
      li = innerul;
    } else {

      li.innerHTML = "<a class='meta'>" + response.data.items[i].label + "</a>"; // create a new li element
      ul.appendChild(li); // every time append a new item
    }
    ul.appendChild(li); // every time append a new item
  }

}

createList({
  data: data
});
<div id="list"></div>

2 Comments

I am getting duplication issues
@user992731 I've updated answer to create sublist in case when there are items available
1

Here's my take. You'll want to use recursion to print out the list.

function printList(list,container){
    var ul = document.createElement('ul');
    list.forEach(function(item){
        var li = document.createElement('li');
        li.innerHTML = '<div class="meta">' + item.label + '</div>';
        if(item.hasOwnProperty('items')){
            printList(item.items,li);
        }
        ul.appendChild(li);
    });
    container.appendChild(ul);
}

To use it:

axios.get('../data/colors.json').then(function (response) {
    printList(response.data.items,document.body);
})

function printList(list,container){
    var ul = document.createElement('ul');
    list.forEach(function(item){
        var li = document.createElement('li');
        li.innerHTML = '<div class="meta">' + item.label + '</div>';
        if(item.hasOwnProperty('items')){
            printList(item.items,li);
        }
        ul.appendChild(li);
    });
  container.appendChild(ul);
}

var items = {
   "items":[
      {
         "label":"red",
         "url":"red",
         "items":[

         ]
      },
      {
         "label":"blue",
         "url":"#/blue",
         "items":[
            {
               "label":"green",
               "url":"#/green"
            },
            {
               "label":"yellow",
               "url":"#/yellow"
            },
            {
               "label":"pink",
               "url":"#/pink"
            }
         ]
      }
     ]
}

printList(items.items,document.body);

console.log();

Comments

1

You can do this with a simple recursive function that accepts the html element you want to append to and an object. An advantage of this approach is that will work to arbitrary depths and it maintains the nesting rather than flattening everything out. Most of the work is manipulating the HTML — other than that it's a very simple idea:

let obj = {"items":[{"label":"red","url":"red","items":[]},{"label":"blue","url":"#/blue","items":[{"label":"green","url":"#/green"},{"label":"yellow","url":"#/yellow"},{"label":"pink","url":"#/pink"}]}]}

function addItems(parent, obj) {
    let keys = Object.keys(obj)
    for (key of keys) {
      let o = obj[key]      
      let li = document.createElement('li')
      if (Array.isArray(o)) {
        let text = document.createTextNode(key);
        li.appendChild(text)
        let ul = document.createElement('ul')
        o.forEach(item => addItems(ul, item))
        li.appendChild(ul)
      } else {
        li.innerText = key + ': ' + o
      }
      parent.appendChild(li)
    }
}

let list = document.getElementById('1')
addItems(list, obj)
<ul id="1">
</ul>

Comments

0

I don't think that you are looping over the nested items array. You are only looping over the parent array.

If there are items in the nested array, add another loop for it. For example

for (var j in response.data.items[i].items) {
  li.innerHTML = "<a class='meta'>" + response.data.items[i].label + "<div>" + response.data.items[i].items[j].label + "</div>" + "</a>"; // create a new li element
}

I think there are better patterns to do a for loop, but I am just keeping your pattern here. Basically root cause, you aren't looping over the nested items.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.