Home > Blockchain >  Modify value in a deeply nested object and return the new object in Javascript
Modify value in a deeply nested object and return the new object in Javascript

Time:06-02

I want to modify a property in deeply nested object in Javascript and return the modified object. For eg, I am rendering checkboxes in my application and the structure looks like below,

{
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: false,
          }
        }
      }
    }
  }
}

I am rendering the above structure like below, Rendered checkboxes

Now, if a user clicks on any of the checkboxes, I want to return the modified object with the updated state, so let's say if the user clicked on level4 checkbox, I want the below object to be returned. Also, I have the key corresponding to the checked checkbox, so for above scenario, i have 'level4'.

{
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: true,
          }
        }
      }
    }
  }
}

I wrote the below function to modify the value, but facing difficulty in returning a new object. Also, the object could be deeply nested to any level,

function changeVal(obj, checkedKey) {
    for(const key in obj) {
        if(key === 'subLevels' && typeof obj.subLevels === 'object') {
            changeVal(obj[key].subLevels);
        } 
        if(key === checkedKey) {
            obj[key].checked = !obj[key].checked;
        } 
    }
}

Could you please help out?

CodePudding user response:

Presented below is one possible way to achieve the desired objective.

Code Snippet

const myUpdate = (obj, k) => (
  [k] in obj
    ? obj[k].checked = !obj[k].checked
    : Object.values(obj).forEach(
        v => myUpdate(v?.subLevels ?? {}, k)
      ),
  obj
);

/* EXPLANATION of the code ---
// method to update a "cloned" object
// the caller passes a deep-cloned object
// by using "structuredClone()"
const myUpdate = (obj, k) => {
  // if "k" (say "level4") is in "obj"
  if ([k] in obj) {
  // just flip the "checked" prop (false to true, or vice-versa)
    obj[k].checked = !obj[k].checked
  } else {
  // else, recursive call using the "subLevels" prop
  // if there are no values in obj or no "subLevels"
  // simply pass empty object for recursion
    Object.values(obj).forEach(
      v => myUpdate(v?.subLevels ?? {}, k)
    )
  };
  // always return "obj"
  return obj;
};
*/

const dataObj = {
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: false,
          }
        }
      }
    }
  }
};

console.log(
  '\n\n setting level-4 to true :\n',
  myUpdate(structuredClone(dataObj), 'level4'),
  '\n\n setting level-3 to false :\n',
  myUpdate(structuredClone(dataObj), 'level3'),
  '\n\nand now the existing obj, un-altered:\n',
  dataObj,
);
.as-console-wrapper { max-height: 100% !important; top: 0 }

Explanation

Comments added to the snippet above.

CodePudding user response:

var data = {
    level1: {
    name: 'Level 1',
    key: 'level1',
    checked: false,
    subLevels: {
      level2: {
        name: 'Level 2',
        key: 'level2',
        checked: false,
        subLevels: {
          level3: {
            name: 'Level 3',
            key: 'level3',
            checked: true,
          },
          level4: {
            name: 'Level 4',
            key: 'level4',
            checked: false,
          }
        }
      }
    }
  }
}


var newJsonObject = traverseNesteddata(data, "level4");
console.log(newJsonObject);

var keepTheLevel4;
function traverseNesteddata(data, checkedKey){
    for(var singleValue in data){
        if(typeof data[singleValue] == 'object'){
            traverseNesteddata(data[singleValue], checkedKey);
        }else{
           if(data[singleValue] === checkedKey)
           {
           if(data.checked === false)
           data.checked = true;
           else
           data.checked = false;
        }}
    }
    
    return data;
}

  • Related