Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Iterating through unknown-depth object

Bit of history to what I'm doing...
I've got a php script which will scan a directory (and all subdirectories, and sub-sub, etc), and will store that in an array, then convert it into a JSON (forced-object) string.

I then have a javascript AJAX query which will grab the JSON string from the php page and parse it back into a javascript object.

What i'm trying to do is iterate through the object (of unknown depth), and display it as a list. If it is a file, give it a <a onclick=""></a>, if it is a folder, give it a sublist <li>foldername<ul><li>contents</li></ul></li>

So, what I'm hoping to generate would look something like this...

<li><a onclick="">someFile</a></li>
<li><a onclick="">anotherFile</a></li>
<li>someFolder
  <ul>
    <li><a onclick="">deeperFile</a></li>
    <li><a onlick="">anotherDeeperFile</a></li>
  </ul>
</li>

Example only goes 2 deep, but hopefully you guys get the idea :)

I've got code that will deal with filenames on the top level. Just not any folders (objects).
I pass it the array of objects, and it iterates through...

function populateFunctions(arr){

  var genHTML = "";
  for (key in arr){
    if (typeof arr[key] === "string"){
      var fname = arr[key]
      //remove the extension, don't need it
      fname = fname.substring(0, fname.length - 4);
      genHTML = genHTML + "<li><a onClick=\"\">" + fname + "</a></li>\n";
    } else {
    }

  }
    return genHTML;
  }
}

I read here (Iterate over a JavaScript array without using nested for-loops) about using a recursive function...
however, I want to store the value until its finished iterating completely...

I guess using a variable in a higher scope (probably 'global') would work, just append the value to the variable each time the function runs... but is there another way?
and am I on the right track? or is there a better/more efficient way?

A lot of the stuff I've found is about iterating multi-dimensional arrays/objects of known depth, whereas here, the depth will be as deep as the directory structure.

Here is the JSON object that I am playing with atm
{"mainPackage":{"0":"test.xml"},"somePackage":{"0":"anotherFunction.xml","deeper":{"0":"ohYouFoundMe.xml"},"1":"someFunction.xml"}}

If any more code etc is needed, lemme know.
Thanks in advance for any help :)

like image 981
Kieran Avatar asked Aug 14 '26 22:08

Kieran


1 Answers

Just iterate through everything like this:

function populateFunction(arr){
    var mainContain=document.createElement('ul');
    function iterateThrough(obj,elt){
        Object.keys(obj).forEach(function(curKey){
            if(typeof obj[curKey]==='object'){
                var li=document.createElement('li');
                var tn=document.createTextNode(curKey);
                var ul=document.createElement('ul');
                li.appendChild(tn);
                li.appendChild(ul);
                elt.appendChild(li);
                iterateThrough(obj[curKey],ul);
            }
            else{
                var li=document.createElement('li');
                var aElt=document.createElement('a');
                //you'd want to add other stuff (such as href or onclick) to the a element here
                aElt.textContent=curKey;
                li.appendChild(aElt);
                elt.appendChild(li);
            }
        });
    }
    iterateThrough(arr,mainContain);
    return mainContain;
}

I'm not sure if that technically qualifies as a recursive function, as it doesn't rely on return, but it does basically that. Also note that it returns a DOM element, not a string like your original, incomplete function does, so you need to take that into account. Working example: http://jsfiddle.net/BWn9t/

like image 154
markasoftware Avatar answered Aug 16 '26 12:08

markasoftware



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!