What is the best way to organize objects based on their keys?

Looking to iterate through object values and append text if the key matches in JavaScript. The object is as follows:

{
    "id": "n27",
    "name": "Thomas More",
    "className": "level-1",
    "children": [
        {
            "id": "n1",
            "name": "Rousseau",
            "className": "level-2",
            "children": [
                {
                    "id": "n2",
                    "name": "Machiavelli",
                    "className": "level-3",
                    "children": [
                        {
                            "id": "n9",
                            "name": "Edison, Thomas",
                            "className": "level-4"
                        }
                    ]
                }
            ]
        },
        {
            "id": "n3",
            "name": "Einstein",
            "className": "level-2",
            "children": [
                {
                    "id": "n10",
                    "name": "Arf, Cahit",
                    "className": "level-3",
                    "children": [
                        {
                            "id": "n15",
                            "name": "Rawls, John",
                            "className": "level-4"
                        }
                    ]
                },
                {
                    "id": "n12",
                    "name": "Smith, Adam",
                    "className": "level-3",
                    "children": [
                        {
                            "id": "n11",
                            "name": "Kant, Immanuel",
                            "className": "level-4"
                        }
                    ]
                }
            ]
        },
        {
            "id": "n60",
            "name": "Turing, Alan",
            "className": "level-2"
        }
    ]
}

The goal is to include " YES" to their existing className's. The updated object should appear like this:

{
    "id": "n27",
    "name": "Thomas More",
    "className": "level-1 YES",
    "children": [
        {
            "id": "n1",
            "name": "Rousseau",
            "className": "level-2 YES",
            "children": [
                {
                    "id": "n2",
                    "name": "Machiavelli",
                    "className": "level-3 YES",
                    "children": [
                        {
                            "id": "n9",
                            "name": "Edison, Thomas",
                            "className": "level-4 YES"
                        }
                    ]
                }
            ]
        },
        {
            "id": "n3",
            "name": "Einstein",
            "className": "level-2 YES",
            "children": [
                {
                    "id": "n10",
                    "name": "Arf, Cahit",
                    "className": "level-3 YES",
                    "children": [
                        {
                            "id": "n15",
                            "name": "Rawls, John",
                            "className": "level-4 YES"
                        }
                    ]
                },
                {
                    "id": "n12",
                    "name": "Smith, Adam",
                    "className": "level-3 YES",
                    "children": [
                        {
                            "id": "n11",
                            "name": "Kant, Immanuel",
                            "className": "level-4 YES"
                        }
                    ]
                }
            ]
        },
        {
            "id": "n60",
            "name": "Turing, Alan",
            "className": "level-2 YES"
        }
    ]
}

I attempted to achieve this but it applies to all keys:

const addToClassName = (datasource, fn) => {
    return Object.fromEntries(Object
        .entries(datasource, fn)
        .map(([k, v]) => [k, v && v.children != undefined && v.children.length > 0 ? addToClassName(v.children, fn) : fn(v)])
    );
}

let res = addToClassName(obj, v => v + ' YEP');

Any suggestions on how to accomplish this?

Answer №1

To avoid using Object.fromEntries(), consider having your function generate a new object that includes a modified className based on the return value of fn. You can then assign the mapped version of all objects within the children array to the key children: in the object. During mapping, each child can be passed into a recursive call of your addToClassName() function. Conditionally add the children key to the output object by checking its existence (using children &&) and spreading the result with the spread syntax ...:

const data = { "id": "n27", "name": "Thomas More", "className": "level-1", "children": [ { "id": "n1", "name": "Rousseau", "className": "level-2", "children": [ { "id": "n2", "name": "Machiavelli", "className": "level-3", "children": [ { "id": "n9", "name": "Edison, Thomas", "className": "level-4" } ] } ] }, { "id": "n3", "name": "Einstein", "className": "level-2", "children": [ { "id": "n10", "name": "Arf, Cahit", "className": "level-3", "children": [ { "id": "n15", "name": "Rawls, John", "className": "level-4" } ] }, { "id": "n12", "name": "Smith, Adam", "className": "level-3", "children": [ { "id": "n11", "name": "Kant, Immanuel", "className": "level-4" } ] } ] }, { "id": "n60", "name": "Turing, Alan", "className": "level-2" } ] };
const addToClassName = (obj, fn) => ({
  ...obj, 
  className: fn(obj.className), 
  ...(obj.children && {children: obj.children.map(child => addToClassName(child, fn))})
});

console.log(addToClassName(data, v => v + " YES"));

Answer №2

To implement changes to the existing obj object, you can utilize recursion in the following manner:

function applyStyle(obj) {
  obj.style += " highlight";
  obj.children && obj.children.forEach(applyStyle);
}
const obj = {
  id: "n27",
  name: "Thomas More",
  style: "bold",
  children: [
    {
      id: "n1",
      name: "Rousseau",
      style: "italics",
      children: [
        {
          id: "n2",
          name: "Machiavelli",
          style: "underline",
          children: [
            {
              id: "n9",
              name: "Edison, Thomas",
              style: "highlight",
            },
          ],
        },
      ],
    },
    {
      id: "n3",
      name: "Einstein",
      style: "normal",
      children: [
        {
          id: "n10",
          name: "Arf, Cahit",
          style: "italics",
          children: [
            {
              id: "n15",
              name: "Rawls, John",
              style: "highlight",
            },
          ],
        },
        {
          id: "n12",
          name: "Smith, Adam",
          style: "underline",
          children: [
            {
              id: "n11",
              name: "Kant, Immanuel",
              style: "highlight",
            },
          ],
        },
      ],
    },
    {
      id: "n60",
      name: "Turing, Alan",
      style: "strikethrough",
    },
  ],
};

function addClass(obj) {
  obj.style += " highlight";
  obj.children && obj.children.forEach(addClass);
}

addClass(obj);
console.log(obj);

Answer №3

If you're receptive to the idea, consider making use of lodash.

const _ = require('lodash');
const data = { "id": "n27", "name": "Thomas More", "className": "level-1", "children": [ { "id": "n1", "name": "Rousseau", "className": "level-2", "children": [ { "id": "n2", "name": "Machiavelli", "className": "level-3", "children": [ { "id": "n9", "name": "Edison, Thomas", "className": "level-4" } ] } ] }, { "id": "n3", "name&...
</answer3>
<exanswer3><div class="answer" i="69784635" l="4.0" c="1635653442" m="1635665596" v="1" a="QTFleGFuZHIgQmVsYW4=" ai="87713">
<p>If it suits your preferences, feel free to implement <strong>lodash</strong>.</p>
<pre><code>const _ = require('lodash');
const data = { "id": "n27", "name": "Thomas More", "className": "level-1", "children": [ { "id": "n1", "name": "Rousseau", "className": "level-2", "children": [ { "id": "n2", "name": "Machiavelli", "className": "level-3", "children": [ { "id": "n9", "name": "Edison, Thomas", "className": "level-4" } ] } ] }, { "id": "n3", "name": "Einstein", "className": ...</answer3>
<exanswer3><div class="answer" i="69784635" l="4.0" c="1635653442" m="1635665596" v="1" a="QTFleGFuZHIgQmVsYW4=" ai="87713">
<p>If you are open to it, think about leveraging <strong>lodash</strong>.</p>
<pre><code>const _ = require('lodash');
const data = { "id": "n27", "name": "Thomas More", "className": "level-1", "children": [ { "id": "n1", "name": "Rousseau", "className": "level-2", "children": [ { "id": "n2", "name": "Machiavelli", "className": "level-3", "children": [ { "id": "n9", "name": "Edison, Thomas", "className": "level-4" } ] } ] }, { "id": "n3", "name": "Einstein", "className": "level-2", "children": [ { "id": "n10", "name": "Arf, Cahit", "className": "level-3", "children": [ { "id": "n15", "name": "Rawls, John&q...</answer3>
<exanswer3><div class="answer" i="69784635" l="4.0" c="1635653442" m="1635665596" v="1" a="QTFleGFuZHIgQmVsYW4=" ai="87713">
<p>If you don't mind, give <strong>lodash</strong> a try.</p>
<pre><code>const _ = require('lodash');
const data = { "id": "n27", "name": "Thomas More", "className": "level-1", "children": [ { "id": "n1", "name": "Rousseau", "className": "level-2", "children": [ { "id": "n2", "name": "Machiavelli", "className": "level-3", "children": [ { "id": "n9", "name": "Edison, Thomas", "className": "level-4" } ] } ] }, { "id": "n3", "name": "Einstein", "className": "level-2", "children": [ { "id": "n10", "name": "Arf, Cahit", "className": "level-3", "children": [ { "id": "n15", "name": "Rawls, John", "className": "level-4" } ] }, { "id": "n12", "name": "Smith, Adam", "className": "level-3", "children": [ { "id": "n11", "name": "Kant, Immanuel", "className": "level-4" } ] } ] }, { "id": "n60", "name": "Turing, Alan", "className": "level-2" } ] };

const newData= _.cloneDeepWith(data, (val, key) => (
  (key === 'className') ? `${val} YES` : _.noop()
));

console.log(newData);
// {
//   id: 'n27',
//   name: 'Thomas More',
//   className: 'level-1 YES',
// ...
// }

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

Nuxt.js - Struggling to Remove Event Listener

I am currently utilizing nuxt.js and have implemented a scroller that scrolls and stops at a specific point on my page. However, when I navigate to the next page, the method is still searching for the element with $ref=nav which no longer exists, resultin ...

"Enhance Your Website's User Experience with jQuery Aut

One of the challenges I am facing involves an Ajax call that retrieves a JSON representation of data created using PHP's json_encode method: ["Montérégie","Montréal - North Shore","Montréal - South Shore"] These values are extracted from a &apos ...

Showing the values of two distinct select boxes in a URL

Here are both select boxes, the goal is to display selected values from both in the URL. This can be achieved by displaying them like this: e.g www.example.com#135+#140 OR www.example.com#135&140 (The order of values doesn't matter as long as bot ...

Mongoose is struggling to locate the expected result

I currently have three different schemas set up. User.js: const mongoose = require("mongoose"); const bcrypt = require("bcryptjs"); const userSchema = new mongoose.Schema({ name: { type: String, required: true, }, email: { type: String, ...

Update the content of the document element by assigning it a lengthy string

I'm utilizing JQuery to dynamically assign content to a div element. The content has numerous lines with specific spacing, so this is the approach I am taking: document.getElementById('body').innerHTML = "Front-End Developer: A <br/> ...

Javascript recursive method for fetching data entries

Seeking a solution to retrieve interconnected records based on a parent column, where the relation can be one or many on both ends. After attempting a recursive function without success, I found my code became overly complex and ineffective. Is there a st ...

Loading drop-down menu content after making an AJAX request

I understand that AJAX functions asynchronously (hence the "A" in AJAX). I have placed all the code that relies on the result of the AJAX call inside the success callback function. However, even after making the call, the select dropdown box is not being p ...

Searching live with array in PHP

I am currently implementing a live search feature on my website using AJAX and PHP. Despite trying to use XML, I didn't find it suitable for my needs. I prefer updating search results easily, which is more manageable with a database. Here's the ...

What is the process for obtaining all of the options from a jQuery datepicker in order to create a new datepicker with identical settings?

Is there a way to easily replicate all options of a jQuery datepicker when creating a new instance? I am trying to duplicate a table that includes 2 datepickers with different settings. For reference, you can view an example here: http://jsfiddle.net/qwZ5 ...

Updates in dropdown events when options data has been modified

Hey there, I'm wondering about dropdown events. Let's say I have two dropdowns. When a selection is made in the first dropdown, all options in the second dropdown are replaced with new ones. For example, let's say the first dropdown has thes ...

How can we rearrange the newly added row from onRowAdd in Material Table to be displayed at the beginning of the section?

Title. According to the documentation for material table, when using editable with onRowAdd, the new row is always added at the bottom of the section. Is there a way to have it appear at the top instead? Alternatively, how can I add an onClick effect so t ...

Column 'Array' does not exist in the 'where clause'. SQL command: SELECT * FROM #__content WHERE Array = '4'

My first time posting here... I encountered a problem with a PHP file that was modified, but not by me. I discovered this error in a menu item: 1054 Unknown column 'Array' in 'where clause' SQL=SELECT * FROM #__content WHERE Array = &ap ...

AngularJS Jasmine test failure: Module instantiation failed

Everything was running smoothly with my angular app and tests using karma and jasmine. However, after adding a dependency in ui.bootstrap, my app continues to function as expected but now my tests won't run. Here is what I have: app.js - added depend ...

Adding data from two different arrays to a MySQL table using PHP

I am attempting to populate a table with values from two arrays. The goal is to insert the corresponding values from array1 and array2 into the table as rows. For example, the table row should look like this: value1, array1[0], array2[0] ... value1, array ...

Having trouble accessing the name property of a select dropdown in Material UI React

Currently, I am facing an issue with implementing a select dropdown. When handling the onChange method, I am encountering a situation where event.target.name is undefined. Specifically, when I choose the 1st option, I want to be able to access 'Englis ...

How can I retrieve a DOM object following an AJAX request?

My AJAX call fetches and appends HTML content to the current page. I hope to access this newly added HTML using standard jQuery selectors. Here's my desired approach... $.ajax({ url: url, success: function(data) { $('body').app ...

The art of concealing and compressing JavaScript code

Can modern JavaScript obfuscation and minification tools effectively protect my code from reverse engineering? Which obfuscation platforms are the most reliable in thwarting these attempts? Is it possible that a program could easily deobfuscate the code, ...

What is the best way to save a jQuery or JavaScript variable into a JSON file?

Is there a way to save a jquery variable in a json file? I have the following: var image='/test/test.png'; I am obtaining this path through file upload: <input type="file" name="imageurl" value="imagefile"></input> Therefore, I ne ...

How can I retrieve the value of $_POST[] immediately after a selection is made in a dropdown box

Is there a way to retrieve the $_POST value immediately after changing the select option without having to submit the form? <select name="cat_id" class="form-control" onChange="this.form.submit();" style="width:300px;"> <?php ...

The Ultimate Guide on Merging Arrays with Identical Keys

I have 2 arrays that look like this ... var arr1 = [ {"Name": "DH", "TotalSel": 11700.0}, {"Name": "PD", "TotalSel": 7000.0}, {"Name": "AT", "TotalSel": 3000.0}, {"Name": "CC", "TotalSel": 2400.0} ]; var arr2 = [ {"Name": "PD", "TotalBuy": 7800 ...