3

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 :)

4
  • please, try to avoid for in loops. It's better to iterate using Object.keys. This isn't an answer, it's just a good practice to make your coding better in general and avoid bugs Commented May 19, 2014 at 2:49
  • 1
    also, use DOM instead of HTML as strings Commented May 19, 2014 at 2:50
  • Recursive function which passes along the object you want to keep your counters in would be a bit nicer than a global. Also, consider building your genHTML in the DOM instead of as a big string. Especially on phones, it'll be quite a bit faster to just directly append into the document than parsing out the string. If you only care about outputting the HTML, you may avoid any kind of variable scoping issues completely if you just appendChild() a <ul> for every recursion, and an <li> inside the function as you loop. Commented May 19, 2014 at 2:50
  • Ok, thanks, will keep that in mind :) And I didn't actually think of passing the information it generated back to itself, not a bad idea :) Commented May 19, 2014 at 2:50

1 Answer 1

4

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/

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

1 Comment

Thanks heaps, this pretty much solves what I'm after :)

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.