Home > Enterprise >  Javascript - Deeply change property value inside array of objects?
Javascript - Deeply change property value inside array of objects?

Time:07-30

I have an array of objects. Each object looks like this:

{
    "key": "pQSa6jgmsbFnQgJ1memDJ",
    "type": "div",
    "props": {
        "id": "pQSa6jgmsbFnQgJ1memDJ",
        "style": {
            "height": "100px",
            "backgroundColor": "#de4141"
        },
        "className": ""
    },
    "selected": true,
    "childNodes": [{
        "key": "pQSa6jgmsbFnQgJ1memDJ",
        "type": "div",
        "props": {
            "id": "VrrQ1rMUOF6IOOKAZomor",
            "style": {
                "height": "100px",
                "backgroundColor": "#de4141"
            },
            "className": ""
        },
        "selected": false,
        "childNodes": []
    }]
}

The problem is that each object can have childNodes, and those childs can have also more childs... The property that I want to change is selected. This property defines wether the object is selected or not and therefore display a different className in the DOM. I have a function to deselect all (change all the object's selected property to false) that looks like this, where content is a React state, the array containing this objects:

function () {
      const $ = _.cloneDeep(content);
      const z = $.map((c) => {
        let y = c;
        if (y?.childNodes && y.childNodes.length > 0) {
          y.childNodes = y.childNodes.map((h) => {
            let x = h;
            x.selected = false;
            return x;
          });
        }
        y.selected = false;
        return y;
      });
      setContent(z);

      setActive(null);
}

But this will only change the first childNodes. What if these childNodes have also more childNodes? I would need to do a map, again, for those childNodes manually. Is there a way to do this (e.g using lodash,which I'm alreay using for cloneDeep())?

CodePudding user response:

You could use a recursive approach to set the required property values. We'd create a function like 'setPropertyDeep', pass along the property value required.

This will update the object tree to any depth.

const input = { "key": "pQSa6jgmsbFnQgJ1memDJ", "type": "div", "props": { "id": "pQSa6jgmsbFnQgJ1memDJ", "style": { "height": "100px", "backgroundColor": "#de4141" }, "className": "" }, "selected": true, "childNodes": [{ "key": "pQSa6jgmsbFnQgJ1memDJ", "type": "div", "props": { "id": "VrrQ1rMUOF6IOOKAZomor", "style": { "height": "100px", "backgroundColor": "#de4141" }, "className": "" }, "selected": false, "childNodes": [] }] }

function updatePropertyDeep(obj, property, value) {
    for(let k in obj) {
       if (k === property) {
           obj[property] = value;
       } else if (obj[k] && typeof(obj[k]) === 'object') { 
           updatePropertyDeep(obj[k], property, value);
       }
    }
    return obj;
}

console.log('Setting true:', updatePropertyDeep(input, 'selected', true))
console.log('Setting false:', updatePropertyDeep(input, 'selected', false))
.as-console-wrapper { max-height: 100% !important; }

CodePudding user response:

use recursion

function updateChild(child){
  if (!child || !Array.isArray(child)) {
    return
  }
  return child.map(el => {
    return {
      ...el,
      selected: false,
      childNodes: updateChild(el.childNodes)
    }
  })
}

function main() {
      return updateChild(content);
      //setContent(z);
      //setActive(null);
      
}

const content = [
  {
    "key": "pQSa6jgmsbFnQgJ1memDJ",
    "type": "div",
    "props": {
        "id": "pQSa6jgmsbFnQgJ1memDJ",
        "style": {
            "height": "100px",
            "backgroundColor": "#de4141"
        },
        "className": ""
    },
    "selected": true,
    "childNodes": [{
        "key": "pQSa6jgmsbFnQgJ1memDJ",
        "type": "div",
        "props": {
            "id": "VrrQ1rMUOF6IOOKAZomor",
            "style": {
                "height": "100px",
                "backgroundColor": "#de4141"
            },
            "className": ""
        },
        "selected": false,
        "childNodes": []
    }]
}
]

document.getElementById('result').innerHTML = JSON.stringify(main(), null, 2)
<pre id="result"></pre>

  • Related