JavaScript - exploring techniques to alter the relationship between parents and children

I'm facing an issue with transforming the parent-child relationship in my data structure. Currently, it looks like this:

{
    "id": 7,
    "name": "Folder 1",
    "parent_folder": null,
    "folders": [
        {
            "id": 8,
            "name": "Folder 1-1",
            "parent_folder": 7
        },
        {
            "id": 10,
            "name": "Folder 1-2",
            "parent_folder": 7
        }
    ],
},
{
    "id": 8,
    "name": "Folder 1-1",
    "parent_folder": 7,
    "folders": [
        {
            "id": 9,
            "name": "Folder 1-1-1",
            "parent_folder": 8
        }
    ],
},
{
    "id": 9,
    "name": "Folder 1-1-1",
    "parent_folder": 8,
}

Each folder has its own representation, containing the ID of its parent_folder and its children (only one level down).

The complexity arises when I attempt to navigate deeper into the structure. While I can create a structure like this:

Folder 1
    Folder 1-1
    Folder 1-2

the problem occurs when I try to add Folder 1-1-1.

To address this challenge, I have devised a solution which is detailed below. The process involves retrieving folder data from an API endpoint and working solely on that response. The snippet begins after fetching the response:

var tempFolderList = [];


var f = response.data.folders;

for (var folder in f) {
  if (f[folder].parent_folder) {
    console.log("PARENT TEMPLATE FOLDER FOUND");

    // Create temporary variable
    var tempChildFolder = {
      id: f[folder].id,
      name: f[folder].name,
      parent_folder: f[folder].parent_folder,
      children: [],
    };

    var attv = this.addToTree(tempFolderList, folder, tempChildFolder, f)
    console.log("attv: " + attv)

    if (attv) {
      this.tempFolderList = attv
    }
    else {
      tempFolderList.push(tempChildFolder)
    }

    // Check if id from current iteration is in temp Folder list
    // if yes add to the list, if not :TODO:
    // if (
    //   tempFolderList.find(
    //     (x) => x.id === f[folder].parent_folder
    //   )
    // ) {
    //   tempFolderList
    //     .find((x) => x.id === f[folder].parent_folder)
    //     .children.push(tempChildFolder);
    // }
  } else {
    // If folder do not have parent folder, just add to temp folder list
    var tempFolder = {
      id: f[folder].id,
      name: f[folder].name,
      parent_folder: f[folder].parent_folder,
      children: [],
    };
    tempFolderList.push(tempFolder);
  }
    console.log(tempFolderList);
}

Below is the addToTree function that empowers the recursive traversal:

addToTree(tempFolderList, folder, tempChildFolder, folderList) {
  if (tempFolderList.find((x) => x.id === folderList[folder].parent_folder)) {
    // tempFolderList.find((x) => x.id === f[folder].parent_folder).children.push(tempChildFolder)
    tempFolderList.push(tempChildFolder)
    return tempFolderList;
  }
  else {
    for (var f in tempFolderList) {
      var attt = this.addToTree(tempFolderList[f].children, folder, tempChildFolder, folderList)
      if (attt) {
        tempFolderList[f] = attt
        return tempFolderList
      }
      else {
        return false
      }
    }
  }
    },

Answer №1

To start, establish a folder map using its unique ID for quick retrieval in the future:

let folders = response.data.folders

let folderMap = folders.reduce((map, folder) => {
  map[folder.id] = folder
  return map
}, {})

Next, filter out only the top-level root folders:

let folderTree = folders.filter(folder => folder.parent_folder === null)

Then, recursively resolve the children within each folder:

let resolveFolder = function (folder) {
  let newFolder = { ...folderMap[folder.id] } // Perform a shallow copy of the folder object to prevent mutation
  if (newFolder.folders) {
    newFolder.folders = newFolder.folders.map(resolveFolder)
  }
  return newFolder
}

folderTree.map(resolveFolder)

let folders = [
  {
    "id": 7,
    "name": "Folder 1",
    "parent_folder": null,
    "folders": [
      {
        "id": 8,
        "name": "Folder 1-1",
        "parent_folder": 7
      },
      {
        "id": 10,
        "name": "Folder 1-2",
        "parent_folder": 7
      }
    ]
  },
  {
    "id": 8,
    "name": "Folder 1-1",
    "parent_folder": 7,
    "folders": [
      {
        "id": 9,
        "name": "Folder 1-1-1",
        "parent_folder": 8
      }
    ]
  },
  {
    "id": 9,
    "name": "Folder 1-1-1",
    "parent_folder": 8
  },
  {
    "id": 10,
    "name": "Folder 1-2",
    "parent_folder": 7
  }
]

let folderMap = folders.reduce((map, folder) => {
  map[folder.id] = folder
  return map
}, {})

let resolveFolder = function (folder) {
  return {
    ...folderMap[folder.id],
    folders: folderMap[folder.id].folders?.map(resolveFolder)
  }
}

let folderTree = folders
  .filter(folder => folder.parent_folder === null)
  .map(resolveFolder)

console.log(folderTree)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Trouble displaying AngularJS $scope.data in the HTML code

I'm experiencing an issue where the data received from a POST request is being logged in the console, but is not displaying on the HTML page. Despite having a controller set up, the {{user}} variable is not appearing on the HTML page. While I can se ...

AngularJS: Functions may return false due to the asynchronous nature of services

Template Overview: <div data-ng-if="budgetSummaryExists()"> <span>You currently have no budget.</span> <button type="button" class="btn btn-danger" data-ng-click="setRoute('budgets')">Creat ...

Guide to sending a similar request as a curl command through a JavaScript file

After reviewing this Stack Overflow post titled "JavaScript post request like a form submit", I came across a similar situation. Currently, I have a curl command that performs as expected: curl -v -X POST -H "application/json" -H "Content-type: applicatio ...

What is the reason behind every single request being treated as an ajax request?

Recently, I embarked on a new application development journey using rails 4.0. However, I've encountered an unexpected situation where every request is being processed as an ajax request. For instance, consider this link: =link_to "View detail", pr ...

How to filter jQuery DataTables by column using comparison operators

Recently, I've been utilizing the amazing DataTables jQuery plugin along with the filter plug in. But now, I find myself pondering if there's a way to filter table columns by row using a comparison operator (such as '<', '>', ...

Using React to Render a Component with Local Storage Information

I'm in the process of developing a history list component for a form within a react application and encountering difficulties with local storage. The goal is to display a list of previous user inputs from the local storage data. My current approach i ...

When an attempt to make a POST request using fetch() is made, a TypeError: Failed to fetch error is immediately thrown instead of

My front-end form is posting data using the fetch() function. Everything works fine and I get the correct response from the server when it runs smoothly without any interruptions. However, when I debug the server endpoint, it throws a TypeError: failed to ...

Angular directive preventing default action but Chrome still loading image on drag

Has anyone encountered an issue with an angular directive that is not successfully preventing Chrome's default action? Below is the code for the directive in question: app.directive('fileDrag', function () { return { restrict: ' ...

Incorporating Javascript into a .Net MVC 3 Project

It seems like there should be a straightforward solution to my question, but I'm struggling with it. I have an animation.js file that includes dependency_1.js and dependency_2.js in an include folder. Within my animation.js file, I load these dependen ...

Secrets to concealing a Material UI column based on specific conditions?

Recently, I encountered a challenge with my MUI datagrid where I needed to hide a column based on a specific role. Below is the code snippet: const hideColumn = () => { const globalAdmin = auth.verifyRole(Roles.Admin); if(!globalAdmin){ ...

How can I access and modify objects within a state array in reactJS when using the setState() method?

Upon reviewing my code, I came across the following declaration: constructor(props) { super(props); this.state = { productArray: [{ barcode: '', name: '' }], numberOfRecords: ...

Unlock the Power of Vue Draggable in Vue.js 3 with These Simple Steps

When attempting to implement Draggable in Vue.js 3, I encountered an error message: VueCompilerError: v-slot can only be used on components or <template> tags. Below is a snippet of my code: <draggable tag="transiton-group" name="s ...

The type 'Navigator' does not have the property 'userAgentData' in its definition

Since I'm looking to minimize the information provided by navigator.userAgent, I decided to migrate to User-Agent Client Hints. However, I've encountered an error while attempting to do so: https://i.stack.imgur.com/lgIl7.png Could someone plea ...

What are the steps involved in manipulating objects within an asynchronous result object?

I'm interested in learning how to manipulate a JS object from one file into another asynchronously, as my experience with asynchronous code principles is limited. Scenario: In my app.js file, I dynamically generate 'app panels' based on ...

Having trouble accessing undefined properties in ReactJs? Specifically, encountering issues when trying to read the property "name"?

I am facing an issue with using the data in my console even though I can log it. The structure of my data object is as follows: {_id: '616bf82d16a2951e53f10da4', name: 'abd', email: '[email protected]', phone: '123456789 ...

Angular Circumstance

Can you help me out? I am trying to figure out how to create an IF...ELSE condition using AngularJS on my index.html file: <ons-list-item modifier="chevron" class="list-item-container" ng-repeat="item in categories track by $index"> <a href="#/pa ...

Insert icons in the action columns and in every single row

https://i.stack.imgur.com/4EH91.png In the realm of vue.js, there exists a project tailored for a thriving car sales company. The intricacies lie within a table fuelled with essential information concerning each vehicle, evident in the image provided. Ever ...

Leveraging 'v-for' to construct dropdown options in HTML and setting the key as the value for each option

Here is some HTML code using Vue syntax: <select id='select-id' > <option selected disabled value=''>Select Option</option> <option v-for="(value, key) in object">{{ key }} - {{ value}}</option> </s ...

Regenerating VueJS application prior to executing docker-compose up

Looking to deploy a VueJS app within a Docker Nginx container, but before running the container, the VueJS source needs to be compiled using npm run build. The goal is for the compilation process to happen within a container and then exit, leaving only the ...

Is it advisable to Utilize ES6 Classes in Javascript for Managing React State?

Is it recommended to use ES6 classes directly as React state? I am interested in creating an ES6 class that: Contains member variables that will trigger re-renders on the frontend when changed. Includes methods that sync these member variables with the ...