javascript, nested navbar from json

Viewed 192

My aim is to replicate this structure automatically from a json file.

<ul class="sidebar-menu">
  <li class="treeview">
    Mammals
    <ul class="treeview-menu">
      <li>Goat</li> 
      <li> Sheep
        <ul class="treeview-menu">
          <li>Bone</li>
          <li>Bone
            <ul class="treeview-menu">
              <li>Variant 1</li>
              <li> Variant 2</li>
            </ul>
          </li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

JSON

[
{"datasetID":"5fd4124900827","higherClassification":"Eukarya","kingdom":"Animalia","phylum":"Chordata","class":"Mammalia","order":"Artiodactyla","family":"Bovidae","genus":"Capra","subgenus":"None","vernacularName":"goat","commonName":"None","elementName":"Calcaneus","commonElementName":"None"},
{"datasetID":"5fd4058e5c8d2","higherClassification":"Eukarya","kingdom":"Animalia","phylum":"Chordata","class":"Mammalia","order":"Artiodactyla","family":"Bovidae","genus":"Capra","subgenus":"None","vernacularName":"goat","commonName":"goat","elementName":"Femur","commonElementName":"None"}
]

The relevant parts are:

"datasetID":"5fd4124900827"

"class":"Mammalia",

"order":"Artiodactyla",

"family":"Bovidae",

"genus":"Capra",

"subgenus":"None",

"vernacularName":"goat",

"elementName":"Calcaneus"},

So the class is on the top level of the hierarchy, it could be mammal, bird, fish...

Taking class: Mammalia as an example, under this is order under that family under that genus

then if there is a subgenus that is on the next level also.

Under that is the vernacularName then elementName.

Each record has a unique id datasetID there may be multiple "elementName": "Calcaneus" for a goat, these need an integer added (i.e. Calcaneus 1, then Calcaneus 2, then Calcaneus 3 etc.

>Mammalia
  >order
    >family
      >genus
        >subgenus (if exists)
          >vernacularName
            >elementName (if more than one append 1,2,3...)

So, my mega question, how to do this in javascript?

My attempt so far:

Php gets the json, yes this could be done in javascript.

<?php
$data = json_decode(file_get_contents("bonify" . $version . "/app/json/data.json"), True);
?>

Javascript picks up the json:

<script type="text/javascript">
const version = "<?php echo $version; ?>";
$.getJSON('bonify'+ version +'/app/json/data2.json', function(json) {
    console.log(json); // this will show the info it in firebug console
    obj = json

This lists all the json data:

function printValues(obj) {
    for(var k in obj) {
        if(obj[k] instanceof Object) {
            printValues(obj[k]);
        } else {
            document.write(obj[k] + "<br>");
        };
    }
};

closing code:

  });
</script>

I'm not convinced document.write is the best way to do this.

I have this code for my search and it seems like I should adapt that but with out the filter capability.

 $('#txt-search').keyup(function(){
             var searchField = $(this).val();
            if(searchField === '')  {
                $('#filter-records').html('');
                return;
            }
             var regex = new RegExp(searchField, "i");
             var output = '<div class="col-12 p-0"><hr />';
             var count = 1;
              $.each(data, function(key, val){
                if ((val.datasetID.search(regex) != -1) || (val.ownerInstitutionCode.search(regex) != -1)|| (val.vernacularName.search(regex) != -1)|| (val.elementName.search(regex) != -1)) {
          output += '<ul class="sidebar-menu">';
          output += '<li><a href="bonify/' + val.datasetID + '"><i class="fas fa-bone" data-fa-transform="rotate-45"></i> <span>' + val.vernacularName + ': ' + val.elementName + '</span></a></li>';
          output += '</ul>';
                      if(count%2 == 0){
                    output += '</div>'
                  }
                  count++;
                }
              });
              $('#filter-records').html(output);
         });
   });
 });

I'm assuming several nested foreach loops is the way to go? I've put the whole aim for clarity. I am trying to learn and I have a learning disability so please be patient with me, thanks for your help. I've tried to included as much info as possible to avoid having my question closed as too broad.

1 Answers

You have a repeated pattern. If we assume that you have built a hierarchical data structure, then we can use a function using template literals, like:

function buildChildren(children) {
    var tvms = [];
    for (let child of children) {
        tvms.push(myTreeViewMenu(child));
    }
    return tvms;
}

function myTreeViewMenu(treeViewMenu) {
    tvms = buildChildren(treeViewMenu.children);
    return `
        <ul class="treeview-menu">
            <li>${treeViewMenu.name} ${tvms.join("")}</li>
        </ul>
    `;
}

function myTree(tree) {
    tvms = buildChildren(tree.children);
    return `
        <ul class="sidebar-menu">
            <li class="treeview">
                ${tree.name}
                ${tvms.join("")}
            </li>
        </ul>
    `;
}

(NOT TESTED)

This logic can be a starting point for you, basically you nest your pattern into itself. You need to make sure that from your raw JSON you build an object tree whose nodes have a string called name and an array for the subtree called children. Also, make sure there are no cycles in the tree.

Related