Generate a navigation route based on the hierarchical relationship between parent and child elements

Here is an array of objects:

[
  {
    "id": 1942,
    "label": "1",
    "url": "",
    "homepage": false,
    "visible": true,
    "order": 1
  },
  {
    "id": 1943,
    "label": "a",
    "url": "",
    "parentId": 1942,
    "homepage": false,
    "visible": true,
    "order": 1
  },
  ...

The task at hand is to generate a menu with links based on the parent-child relationships in the array.

The new array structure needed for this purpose should be formatted as follows:

1

1 / a

1 / aa

1 / aaa

1 / a / a1

1 / a / a2

2

2 / b

2 / bb

2 / b / b1

2 / b / b2

Multiple attempts have been made, including recursion and looping techniques:

 convert(array) {
    const x = array
      .filter((m, i) => m.id === array[i].parentId)
      .map((menuItem) => ({
        parent: menuItem,
        children: convert(array),
      }));
      console.log(x)
  }

Yet, none has succeeded in achieving infinite levels of depth. Here is one such attempt:

convert() {
    let parents = array.filter((p) => !p.parentId);
    const children = array.filter((c) => c.parentId);
    let combined = [];
    // Loops used here...
    console.log(combined);
  }

UPDATE: While I managed to achieve 3 levels of depth, recursive solution for unlimited depth remains unresolved.

convert() {
    let parents = this.config.menuItems.filter((p) => !p.parentId);
    const children = this.config.menuItems.filter((c) => c.parentId);
    let combined = [];
    // More loops with 3-level depth...
    console.log(combined);
  }

Answer №1

Below is a recursive approach that I believe will be effective. If you decide not to utilize the page_children_map, you can substitute page_children_map.get(page.id) with

pages.filter(({ parentId }) => parentId === page.id)
.

const pages = [{"id":1942,"label":"1","url":"","homepage":false,"visible":true,"order":1},{"id":1943,"label":"a","url":"","parentId":1942,"homepage":false,"visible":true,"order":1},{"id":1944,"label":"aa","url":"","parentId":1942,"homepage":false,"visible":true,"order":2},{"id":1945,"label":"aaa","url":"","parentId":1942,"homepage":false,"visible":true,"order":3},{"id":1946,"label":"a1","url":"","parentId":1943,"homepage":false,"visible":true,"order":1},{"id":1947,"label":"a2","url":"","parentId":1943,"homepage":false,"visible":true,"order":2},{"id":1948,"label":"2","url":"","homepage":false,"visible":true,"order":2},{"id":1949,"label":"b","url...

// The rest of the code remains unchanged
console.log(res);

Answer №2

Below is a straightforward recursive function:

const data = [{"homepage": false, "id": 1942, "label": "1", "order": 1, "url": "", "visible": true}, {"homepage": false, "id": 1943, "label": "a", "order": 1, "parentId": 1942, "url": "", "visible": true}, {"homepage": false, "id": 1944, "label": "aa", "order": 2, "parentId": 1942, "url": "", "visible": true}, {"homepage": false, "id": 1945, "label": "aaa", "order": 3, "parentId": 1942, "url": "", "visible": true}, {"homepage": false, "id": 1946, "label": "a1", "order": 1, "parentId": 1943, "url": "", "visible": true}, {"homepage": false, "id": 1947, "label": "a2", "order": 2, "parentId": 1943, "url": "", "visible": true}, {"homepage": false, "id": 1948, "label": "2", "order": 2, "url": "", "visible": true}, {"homepage": false, "id": 1949, "label": "b", "order": 1, "parentId": 1948, "url": "", "visible": true}, {"homepage": false, "id": 1950, "label": "b1", "order": 1, "parentId": 1949, "url": "", "visible": true}, {"homepage": false, "id": 1951, "label": "bb", "order": 2, "pare...

const structure = (dataSet, parent = undefined) => 
  dataSet.filter(({parentId}) => parentId === parent) 
         .map((item) => ({...item, children: structure(dataSet, item.id)}))
   
console.log(structure(data))
.as-console-wrapper {max-height: 100% !important; top: 0}

This will generate a slightly altered version of the objects with nested children nodes. I find this format to be the most straightforward.

If you want each level to include both parent and children nodes, simply update the last line of the function like so:

     .map ((item) => ({parent: item, children: structure(dataSet, item.id)}))

If you are concerned about having empty children nodes, it's a bit more complex to exclude them, but not too difficult:

const data = [{"homepage": false, "id": 1942, "label": "1", "order": 1, "url": "", "visible": true}, {"homepage": false, "id": 1943, "label": "a", "order": 1, "parentId": 1942, "url": "", "visible": true}, {"homepage": false, "id": 1944, "label": "aa", "order": 2, "parentId": 1942, "url": "", "visible": true}, {"homepage": false, "id": 1945, "label": "aaa", "order": 3, "parentId": 1942, "url": "", "visible": true}, {"homepage": false, "id": 1946, "label": "a1", "order": 1, "parentId": 1943, "url": "", "visible": true}, {"homepage"...

const structure = (dataset, parent = undefined) =>
  dataset.filter(({parentId}) => parentId === parent)
         .map((item, _, __, kids = structure(dataset, item.id)) => ({
           ...item,
           ...(kids.length ? {children: structure(dataset, item.id)} : {})
         }))
   
console.log(structure(data))
.as-console-wrapper {max-height: 100% !important; top: 0}

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

Extracting public data from social media profiles as displayed in Smartr

Is there any pre-existing API or reference material available for achieving this task? I am interested in accessing public social data without the need for users to manually link their accounts to our site. ...

Purge React Query Data By ID

Identify the Issue: I'm facing a challenge with invalidating my GET query to fetch a single user. I have two query keys in my request, fetch-user and id. This poses an issue when updating the user's information using a PATCH request, as the cach ...

Discovering the most concise string within the array

I've been working on a JavaScript program function that is supposed to return the smallest string in an array, but I keep encountering an error whenever I run it. Below is the code I have written: function findShortestWordAmongMixedElements(arr) { ...

Switch out arbitrary segments of text in JavaScript

I am attempting to replace a randomly selected substring within a string with another substring. Below is the code I am using: function replaceRandomSubstring(str, substr, repl) { var amount = str.match(substr); var newstr = str; if (amount.length != ...

Having trouble with changing images or background images in JavaScript?

Encountering issues with dynamic elements. When I click a button, the following JS function is executed. It displays a stylish CSS alert upon postback and then runs the function. function scrollToTop(sender, args) { window.scrollTo(0, 0); document. ...

Could you provide instructions on how to change mjs files into js format?

Is there a method to change .mjs files to .js files? Some hosting services do not yet support mjs files, so I am interested in converting them to js files. Context: Mozilla's PDFjs has incorporated JavaScript modules (mjs) into their code, but since ...

Tips for sending an email without using MAILTO in JavaScript or jQuery

Today is a great day for many, but unfortunately not for me. I've been struggling with this issue for over two weeks now and can't seem to find a solution anywhere on the internet. Stack Overflow always comes to my rescue when things get really t ...

Update the value of a Vue tree select component using JavaScript

I'm working on a school project using plain JavaScript and needed a tree view select with multiple layers. After extensive searching, I stumbled upon this tool. It's working smoothly, but the one thing that has me stumped is how to change its va ...

Hold off on running addThis

My website utilizes Google Maps along with my own JavaScript functions. Additionally, I am integrating the AddThis JavaScript for social sharing buttons. For optimal performance, I need both my custom JavaScript and Google's JavaScript to load and exe ...

"Error message: Trying to import a component in Angular, but encountering a message stating that the component has no exported

When creating a component named headerComponent and importing it into app.component.ts, an error is encountered stating that 'website/src/app/header/app.headerComponent' has no exported member 'headerComponent'. The code for app.headerC ...

Error: The specified JavaScript library "angular" is not recognized

Attempting to develop a basic Angular application for searching names from an array in the controller. Each time the app is executed, encountering the error 'Uncaught ReferenceError: angular is not defined' in the console. Despite researching sim ...

Vue.js bootstrap-vue input number has a unique MaxLength feature that sets the

Is there a way to limit the input length for an input field from bootstrap-vue? I tried using maxLength, but it seems that it's not supported based on their documentation. If I remove type="number", the limitation works, but then it won't restric ...

Performing an Ajax GET request in jQuery with custom headers and displaying the response in a new tab/window

My AJAX GET request includes header parameters instead of URL parameters, like this: $.ajax({ url: "http://localhost/myendpoint/ABCDE-12345", headers: { 'X-Auth-Token' : myTokenId}, type: "GET", s ...

Mocking functions using Sinon and Asynchronous calls

I am working on a project where I have a file called mainFile that utilizes a method named helperMethod. This method, which resides in a separate file called helperFile, returns a Promise. How can I mock the output of the helperMethod? Here is the structu ...

Child Component in Vue Not Refreshing with Prop Update

I am currently working on updating an 'exercise' prop that is being sent to a 'workout' component in Vue. Within the child component, I have set up a function to emit and increment the current set you are on. The function is successfull ...

Fetching data from a Django view using a JavaScript AJAX POST call

Utilizing Javascript for an asynchronous request to a Django View, I am able to successfully receive data from the POST request. However, I am encountering issues with returning a confirmation message that the process was successful. Despite expecting xhtt ...

Require a secondary navigation bar to remain fixed below the primary navigation bar as the user scrolls upwards

https://i.sstatic.net/esS0T.png Is there a way to make this second nav bar stick under the main nav bar when the user scrolls up? Currently, it sticks behind the main nav bar. I have attempted a few solutions, but I struggle with JavaScript. Here is the c ...

React-Redux-Saga: Only plain objects are allowed for actions. Consider using custom middleware for handling asynchronous actions

Struggling to integrate redux-saga into my react app, I keep encountering this error: Actions must be plain objects. Use custom middleware for async actions. The error appears at: 15 | changeText = event => { > 16 | this.props.chan ...

Establishing Accessor and Mutator Methods

The variables startStopA... and InitialValueA... that were originally in the component TableFields.vue need to be relocated to the store file index.js. However, upon moving them to the store, an error appears stating that setters are not set. I have extens ...

A guide on extracting keywords from the tynt API using JavaScript

Looking to extract the inbound keyword from an API: What would be the best way to use JavaScript to extract and display the value of the inbound keyword from this API? ...