Home > Software design >  Iterate nested objects to build filetree
Iterate nested objects to build filetree

Time:06-21

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.

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?

CodePudding user response:

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

  • Related