Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Iterate nested objects to build filetree

General Info
Working on an online syntax highlighter with operational transformation for collaboration. The idea is that a single project has a filetree (pure html / css) on the left and the editor on the right. Users can create new files / directories as much as they want and obviously nest them.

The Problem
The files and directories are returned by the server as an object:

{
  "files": ["index.html","panel.html"]
  "directory1": {
    "files": ["foo.html"]
    "subdir1": {
      "files": ["somefile.txt"]
    }
    "subdir2": {
      "files": ["somefile.php","other.php"]
    }
  }
  "directory2": {
    "subdir1": {
      "files": ["you_get_the_idea.txt"]
    }
  }
}

The object is correct. Each object within contains an array with the files for that directory and a nested object representing nested directories.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

The problem is that I want to list the directories alphabetically on top and the files alphabetically within, just like any filebrowser does by default. For some reason, I can’t get it done correctly.

What I’ve tried myself

// Containing the object above
const fileData = {};

let iterations = 0;

const iterate = (fileData) => {
    Object.keys(fileData).forEach(key => {
        // It's a directory
        if (typeof fileData[key] === 'object' && fileData[key] !== null && key != 'files') {
            html += '<li><input type="checkbox"/><span>'+key+'</span><ul>';
            iterations++;
            iterate(fileData[key]);
            last = false;
        }
        // It's a file
        else
        {
            for(let i = 0; i < fileData[key].length; i++)
            {
                html += '<li><span>'+fileData[key][i]+'</span></li>';
            }

            for(let i = 0; i < iterations; i++)
            {
                html += '</ul></li>';
            }
            iterations--;
        }
    });
}

In the above example, this would result in:

- index.html
- panel.html
- directory1
-- foo.html
-- subdir1
--- somefile.txt
--- subdir2
---- somefile.php
---- other.php
---- directory2
----- subdir1
------ you_get_the_idea.txt

Running example here: https://jsfiddle.net/jbvhyzu6/ (didn’t put it here because the CSS code is way too long).

While it should result in:

- directory1
-- foo.html
-- subdir1
--- somefile.txt
-- subdir2
--- somefile.php
--- other.php
-- subdir2
--- subdir1
---- you_get_the_idea.txt
- index.html
- panel.html

So my question is: How can I fix this?

>Solution :

You need to treat the nested parts before you process the rest.

const 
    fileData = { files: ["index.html", "panel.html"], directory1: { files: ["foo.html"], subdir1: { files: ["somefile.txt"] }, subdir2: { files: ["somefile.php", "other.php"] } }, directory2: { subdir1: { files: ["you_get_the_idea.txt"] } } },
    iterate = data => Object
        .entries(data)
        .reduce((r, [k, v]) => r + (
            k === 'files'
                ? v.map(s => `<li><span>${s}</span></li>`).join('')
                : `<li><input type="checkbox"/><span>${k}${iterate(v)}</li>`
            ), '<ul>'
        ) + '</ul>';

document.body.innerHTML += iterate(fileData);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading