Question about using array in javascript for web programming

Viewed 78

I have to use the directory array in javascript to display directory for the web. But I don't know how to put the condition in this case.

const directory = [
  { type: 'file', name: 'file1.txt' },
  { type: 'file', name: 'file2.txt' },
  {
    type: 'directory',
    name: 'HTML Files',
    files: [
      { type: 'file', name: 'file1.html' },
      { type: 'file', name: 'file2.html' }
    ]
  },
  { type: 'file', name: 'file3.txt' },
  {
    type: 'directory',
    name: 'JavaScript Files',
    files: [
      { type: 'file', name: 'file1.js' },
      { type: 'file', name: 'file2.js' },
      { type: 'file', name: 'file3.js' }
    ]
  }
];

The part I am writing but I don't know how to check the condition since all types all file:

  var File = '\0';
    if ()
    directory.forEach(eachFile => {
      
      File = File + `<li>${eachFile}</li>`;
    });

and this is my HTML file.

 <div id="directories">
          <header>
            <title>File Directories</title>
          </header>
          <body>
            <h2>Directories</h2>
            <ul id = "displayDirectories"></ul>
          </body>
        </div>

And this is how output should be:

image of the output html to achieve

3 Answers

Since there are multiple levels of the structure, this has to be done recursively, and for that you need a function (that recursively calls itself for each level). The function is simple, it takes a files array and generate the html code (including the <ul> and </ul>) for that array of files, for each item it creates an li element containing the name of that item, if that item is also a directory it calls itself with that directory files array to generate the html of its files and inserts it into the li:

function listEntries(files) {                                              // takes an array of files and generate an html string of the ul element
  let html = "<ul>";                                                       // opening the ul element

  files.forEach(entry => {                                                 // for each entry in the array
    if(entry.type == "file") {                                             // if the entry is a file
      html += "<li>" + entry.name + "</li>";                               // simply add an li element containing the name
    } else {                                                               // otherwise, if it's a directory
      html += "<li>" + entry.name + listEntries(entry.files) + "</li>";    // add an li element containing the name and an ul element of its children, created via calling listEntries on the files array
    }
  });

  return html + "</ul>";                                                   // close the ul and return
}

You can simplify it further by using a reduce instead of forEach and a ternary instead of if/else like so:

function listEntries(files) {
  return files.reduce((html, entry) =>
    html + "<li>" + entry.name + (entry.type === "directory" ? listEntries(entry.files) : "") + "</li>"
  , "<ul>") + "</ul>";
}

Note: Since the ul tags are included in the html, the DOM element that should receive the generated html should not be another ul element, a div will do, like so:

<div id="displayDirectories"></div>

Demo:

function listEntries(files) {
  return files.reduce((html, entry) =>
    html + "<li>" + entry.name + (entry.type === "directory" ? listEntries(entry.files) : "") + "</li>"
  , "<ul>") + "</ul>";
}


const directory = [ { type: 'file', name: 'file1.txt' }, { type: 'file', name: 'file2.txt' }, { type: 'directory', name: 'HTML Files', files: [ { type: 'file', name: 'file1.html' }, { type: 'file', name: 'file2.html' } ] }, { type: 'file', name: 'file3.txt' }, { type: 'directory', name: 'JavaScript Files', files: [ { type: 'file', name: 'file1.js' }, { type: 'file', name: 'file2.js' }, { type: 'file', name: 'file3.js' } ] } ];

document.getElementById("displayDirectories").innerHTML = listEntries(directory);
<div id="displayDirectories"></div>

To map directory you can do it using recurrence and condition to check type of the directory/file. I use map function to iterate over all array elements and then return correct html in list. You can see example below.

const directory = [{
    type: 'file',
    name: 'file1.txt'
  },
  {
    type: 'file',
    name: 'file2.txt'
  },
  {
    type: 'directory',
    name: 'HTML Files',
    files: [{
        type: 'file',
        name: 'file1.html'
      },
      {
        type: 'file',
        name: 'file2.html'
      }
    ]
  },
  {
    type: 'file',
    name: 'file3.txt'
  },
  {
    type: 'directory',
    name: 'JavaScript Files',
    files: [{
        type: 'file',
        name: 'file1.js'
      },
      {
        type: 'file',
        name: 'file2.js'
      },
      {
        type: 'file',
        name: 'file3.js'
      }
    ]
  }
];

const renderDir = (directory) => {
  return directory.map(dir => {
    if (dir.type === 'file') {
      return `<li>${dir.name}</li>`
    }
    return `<li>${dir.name}<ul>${renderDir(dir.files)}</ul></li>`
  }).join('')

}

const output = renderDir(directory);

document.getElementById('output').innerHTML = output;


https://jsfiddle.net/b1rc3js9/

const directory = [
  { type: 'file', name: 'file1.txt' },
  { type: 'file', name: 'file2.txt' },
  {
    type: 'directory',
    name: 'HTML Files',
    files: [
      { type: 'file', name: 'file1.html' },
      { type: 'file', name: 'file2.html' }
    ]
  },
  { type: 'file', name: 'file3.txt' },
  {
    type: 'directory',
    name: 'JavaScript Files',
    files: [
      { type: 'file', name: 'file1.js' },
      { type: 'file', name: 'file2.js' },
      { type: 'file', name: 'file3.js' }
    ]
  }
];


  var File = '\0';
   
    directory.forEach(eachFile => {
    
    
    if(eachFile['type']=="directory"){
       File=File + "<li>"+eachFile['name'];   
       File=File+"<ul>";
       eachFile['files'].forEach(file=>{       
          File=File + "<li>"+file['name']+"</li>";       
       }); 
       File=File+"</ul></li>";
     }else{      
        File = File + "<li>"+eachFile['name']+"</li>";
     }
    });
    
   var ul=document.getElementById('displayDirectories').innerHTML=File;
<div id="directories">
          <header>
            <title>File Directories</title>
          </header>
          <body>
            <h2>Directories</h2>
            <ul id = "displayDirectories"></ul>
          </body>
        </div>

Related