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

An unexpected 'undefined' value is being added to a particular Web API request

I am encountering an issue in my Angular application where the word 'Undefined' is being appended to a specific WebAPI call, causing both registerUser and login requests to fail. Here are the problematic request URLs: Request URL: http://localho ...

`There was an issue with an unfinished string literal.`

Currently, I am utilizing jQuery to display the information from a JSON string generated by PHP and extracted from a database. However, I have encountered an issue where some of the data spans multiple lines... How can I prevent this from triggering an un ...

The power of the V8 JavaScript engine: Understanding v8::Arguments and the versatility of function

I have created a Node.js addon that wraps a C++ standard library element std::map<T1,T2>. The goal is to expose this map as a module with two primary functions: Set for adding new key-value pairs and Get for retrieving values by key. I want to create ...

The submission of the Ajax form is malfunctioning

My attempt to load the php code without refreshing the page is failing with my Ajax code. What could be causing the issue? I prefer not to use jquery or other frameworks. Do you think the problem lies in my javascript code? Should I resort to using jquery ...

Implementing event handlers with 'v-on' on dynamically inserted content using 'v-html' in Vue

Can Vue allow for the addition of v-on events on strings included in v-html? In this scenario, clicking the 'Maggie' link doesn't produce any action. It appears that it's not recognized by Vue. Is there an alternative method to achieve ...

Guide to authenticating with npm using various user accounts for different scopes within the same registry

I am facing an issue with setting up multiple npm authTokens for two different scopes on the same registry. @scope1:registry=https://registry.npmjs.org/ @scope2:registry=https://registry.npmjs.org/ //registry.npmjs.org/:_authToken=${NPM_TOKEN} I have atte ...

Dragging a stack of cards in a game of Solitaire using jQuery UI

I'm currently in the process of creating a Solitaire card game using Javascript. To enable dragging and dropping functionality for the cards, I am utilizing jQueryUI. In the example provided at http://jsfiddle.net/HY8g7/1/, you can see how the cards c ...

Tips for Maintaining the Execution of a JavaScript Function Within a Class until the Browser Window is Closed (Web Development)

The title might be a little confusing, so let me clarify here: I have implemented a popup that appears in the bottom right corner of a specific page on my website. The popup is working as intended (it shows up when the page is initially opened and can be ...

Organize unstructured JSON data using a specific method

My service returns a JSON with irregular data structure as shown below: dataFromService: [ { event_data: '2021-03-18T15:20:31.314Z', // if !null = page event_category: 'news', event_title_en: 'page title ...

Leverage cookies within a custom service in AngularJS

I attempted to implement angular cookies within a custom service, only to encounter the following error: Unknown provider: ngCookiesProvider <- ngCookies <- checkLoginService My approach involves storing modules, controllers, and services in separat ...

Caution: Exercise caution when rendering components in React due to unstable_flushDiscreteUpdates

Trying to utilize map to render a component, but encountering a warning: Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering. MyBooks.js import React, { useState, useEffect } from 'react'; import Action ...

Guide on how to trigger loader page during execution of Selenium code in Python

I am currently developing a Python Flask web application that incorporates Selenium in the backend. One of my objectives is to disable the webpage when the Selenium driver is running to prevent user interference. Below is the code snippet I am using: < ...

Guide to utilizing custom fonts in a VUE application

I'm currently working on my first Vue project and despite following various examples and the official documentation, I am struggling to resolve an issue regarding importing fonts locally in my project. Within my `` tag, I am importing the font that I ...

Unable to attach an event listener to an element fetched from an API

I'm currently in the process of developing a trivia web application using an API, and my goal is to incorporate an event listener onto the button which corresponds to the correct answer. This way, when users click on it, a message will appear confirmi ...

fontawesome issue: "One or more icons could not be located"

I utilized the instructions found on https://fontawesome.com/how-to-use/on-the-web/using-with/vuejs. However, when implementing it as follows: import { library } from '@fortawesome/fontawesome-svg-core' import { faBars } from '@fortawesome ...

What do you mean my cookie isn't working?

I'm going crazy over this! There's a cookie that was set from a response header with the sessionid, visible in dev tools on Chrome and Firefox, but document.cookie shows an empty string. This is what the cookie looks like: Name: sessionid Value ...

A blank screen of errors pops up when attempting to update through a form

Encountering a white error screen when attempting to add an item using a form in Python / Django. I'm currently debugging the issue but lacking information. Any guidance on where to look next would be greatly appreciated. Models.py from __future__ i ...

Obtain the initial Firebase child element without a specific key

Trying to access the first child of a firebase object is my current challenge. The reference is structured as follows: var sitesToVisitRef = firebase.database().ref('sitesToVisit') The reference is confirmed functional as I am able to write to ...

The concept of functions in JavaScript: fact or fiction?

Is there a way to show the message "Yes" or "No" based on the return value of a function without directly using the words true and false, and without utilizing alert? Any suggestions would be greatly appreciated. Thank you. function myFunction { if (Ma ...

JavaScript Function to Retrieve URL Parameter in PHPIn this tutorial

I'm currently working on an HTML5 game where each level has its own dedicated HTML page. The results of each level are saved in a JavaScript variable. My question is, how can I pass this information to the next page using the URL? I was considering ...