1

I'm trying to build a HTML list using a recursive loop from an object structured like this – there are an infinite number of levels of possible depth:

object = {
   "directories":{
      "vegetables":{
         "info":{
            "name":"Vegetables"
         },
         "files":{

         },
         "directories":{
            "green vegetables":{
               "info":{
                  "name":"Green Vegetables"
               },
               "files":{

               },
               "directories":{
                  "lettuce":{
                     "info":{
                        "name":"Lettuce"
                     },
                     "files":{

                     }
                  },
                  "cucumber":{
                     "info":{
                        "name":"Cucumber"
                     },
                     "files":{

                     }
                  }
               }
            },
            "orange vegetables":{
               "info":{
                  "name":"Orange Vegetables"
               },
               "files":{

               },
               "directories":{
                  "3 deep":{
                     "info":{
                        "name":"Carrot"
                     },
                     "files":{

                     }
                  }
               }
            }
         }
      },
      "fruit":{
         "info":{
            "name":"Fruit"
         },
         "files":{

         },
         "directories":{
            "apple":{
               "info":{
                  "name":"Apple"
               },
               "files":{

               }
            }
         }
      }
   }
}

The loop should create a nested html list as follows:

<ul>
    <li>Vegetables
        <ul>
            <li>Green Vegetables
                <ul>
                    <li>Lettuce</li>
                    <li>Cucumber</li>
                </ul>
            </li>
            <li>Orange Vegetables
                <ul>
                    <li>Carrot</li>
                </ul>
            </li>
        </ul>
    </li>
    <li>Fruit
        <ul>
            <li>Apple</li>
        </ul>
    </li>
</ul>

Currently my function looks like this, but currently it gets stuck after the first list item and I'm struggling to get my head around how to call itself correctly recursively:

function loopFilters(val){
    app.navList.push('<ul>');
    $.each(val.directories, function(i, val) {
        app.navList.push('<li>' + directory);
        if(val){
            // console.log('yes', val.directories);
            app.core.addFiltersToPage(val.directories)
        }
        app.navList.push('</li>');
    });
    app.navList.push('</ul>');
}

How can I rewrite my function to work with my Javascript object?

1
  • 1
    Shouldn't you change directory in line 4 to val.info.name? Also, change condition to if (val.directories) and inside the if call loopFilters(val). Should work then Commented Jul 13, 2018 at 18:51

2 Answers 2

1

You could take a recursive approach by taking the directory object and build a new <ul> list with the names as value and check nested directory property.

function getList(directories) {
    return Object
        .values(directories)
        .reduce((ul, { info: { name }, directories }) => {
            var li = document.createElement('li');
            li.appendChild(document.createTextNode(name));
            ul.appendChild(li);
            if (directories) {
                li.appendChild(getList(directories));
            }
            return ul;
        }, document.createElement('ul'));
}

var data = { directories: { vegetables: { info: { name: "Vegetables" }, files: {}, directories: { "green vegetables": { info: { name: "Green Vegetables" }, files: {}, directories: { lettuce: { info: { name: "Lettuce" }, files: {} }, cucumber: { info: { name: "Cucumber" }, files: {} } } }, "orange vegetables": { info: { name: "Orange Vegetables" }, files: {}, directories: { "3 deep": { info: { name: "Carrot" }, files: {} } } } } }, fruit: { info: { name: "Fruit" }, files: {}, directories: { apple: { info: { name: "Apple" }, files: {} } } } } };

document.body.appendChild(getList(data.directories));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

Comments

0

This can be achieved easily with vanilla JS. See below.

const data = {
   "directories":{
      "vegetables":{
         "info":{
            "name":"Vegetables"
         },
         "files":{

         },
         "directories":{
            "green vegetables":{
               "info":{
                  "name":"Green Vegetables"
               },
               "files":{

               },
               "directories":{
                  "lettuce":{
                     "info":{
                        "name":"Lettuce"
                     },
                     "files":{

                     }
                  },
                  "cucumber":{
                     "info":{
                        "name":"Cucumber"
                     },
                     "files":{

                     }
                  }
               }
            },
            "orange vegetables":{
               "info":{
                  "name":"Orange Vegetables"
               },
               "files":{

               },
               "directories":{
                  "3 deep":{
                     "info":{
                        "name":"Carrot"
                     },
                     "files":{

                     }
                  }
               }
            }
         }
      },
      "fruit":{
         "info":{
            "name":"Fruit"
         },
         "files":{

         },
         "directories":{
            "apple":{
               "info":{
                  "name":"Apple"
               },
               "files":{

               }
            }
         }
      }
   }
}

function buildList(dataRoot, elementRoot) {

  // Only continue if there are directories to look at
  if (dataRoot.directories) {
  
    // Create a new list and append it to our current element
    const list = document.createElement('ul');
    elementRoot.appendChild(list);
    Object.keys(dataRoot.directories).forEach(key => {
    
      // Get the directory from the key
      const directory = dataRoot.directories[key];
      
      // Create a text node and a list element to put it in
      const listElement = document.createElement('li');
      const textNode = document.createTextNode(directory.info.name);
      listElement.appendChild(textNode);
      list.appendChild(listElement);
      
      // Continue recursively down now using the current lis element
      buildList(directory, listElement);
    });
  }
}

const rootElement = document.getElementById("root");
buildList(data, rootElement);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="root"></div>

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.