Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript, nested navbar from json

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.

like image 451
Spatial Digger Avatar asked Mar 22 '26 02:03

Spatial Digger


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.

like image 108
Lajos Arpad Avatar answered Mar 24 '26 18:03

Lajos Arpad