Prozrachniy
Prozrachniy

Reputation: 151

Change deeply nested key value of an object if there's an array of key names

I have an object and an array of the same object keys:

var obj = {
 'fieldOne': {
    'fieldTwo': {
        'fieldThree': {
            'fieldFour': {
                'someNestedKey': 'test'
            }
        }
    }
 }
}
var keysArr = ['fieldOne', 'fieldTwo', 'fieldThree', 'fieldFour', 'someNestedKey'];

Is there a way to change the 'someNestedKey' value using the keys array ?

Simply accessing the 'someNestedKey' by indexes won't work, because keys array may have more or less keys in it. I tried somehow using array length, but I can't seem to get it working. I'm relatively new to programming, would much appreciate any help.

Upvotes: 1

Views: 218

Answers (4)

Rajesh
Rajesh

Reputation: 24915

You can try to use eval as well but do refer When is JavaScript's eval() not evil? before using.

Logic:

  • If the object is properly constructed where the path is already initialised, you can create a string that would directly set value. This way you can skip looping.
  • As a fallback, if there is a case where any of the values inside is not initialised, you can loop over path and set it manually.

function updateValue(obj, path, value) {
  try {
    eval("obj[\"" + path.join("\"][\"") + "\"]=" + value)
    console.log("Used Eval")
  } catch (err) {
    path.reduce(function(p, c, i, a) {
      p[c] = (i === a.length - 1) ? value : p[c] || {};
      return p[c];
    }, obj);

    console.log("Used Loop")
  }
}

var obj = {
  'fieldOne': {
    'fieldTwo': {
      'fieldThree': {
        'fieldFour': {
          'someNestedKey': 'test'
        }
      }
    }
  }
}
var keysArr = ['fieldOne', 'fieldTwo', 'fieldThree', 'fieldFour', 'someNestedKey']
var keysArr1 = ['fieldOne', 'fieldTwo', 'fieldThree', 'fieldFive', 'someNestedKey']

updateValue(obj, keysArr, 10);
console.log(obj)

updateValue(obj, keysArr1, 10);
console.log(obj)

Upvotes: 1

dev8080
dev8080

Reputation: 4020

Try this.

var obj = {
 'fieldOne': {
    'fieldTwo': {
        'fieldThree': {
            'fieldFour': {
                'someNestedKey': 'test'
            }
        }
    }
 }
}
var keysArr = ['fieldOne', 'fieldTwo', 'fieldThree', 'fieldFour', 'someNestedKey'];

var setThis = function(obj, keysArr, valueToSet){

var ref=obj ;
keysArr.forEach(function(key, index){
                    if(index==keysArr.length-1)
                      ref[key] = valueToSet ;
                    else
    	                ref = ref[key] ;
              });
  alert(JSON.stringify(obj));
};  

setThis(obj, keysArr, "test123");

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386560

You could take the path and make a check if the following element exist. If not assign an object to the new property.

Return then the value of the property.

At the end assign the value.

function setValue(object, path, value) {
    var way = path.slice(),
        last = way.pop();

    way.reduce(function (r, a) {
        return r[a] = r[a] || {};
    }, object)[last] = value;
}

var obj = { fieldOne: { fieldTwo: { fieldThree: { fieldFour: { someNestedKey: 'test' } } } } },
    keysArr = ['fieldOne', 'fieldTwo', 'fieldThree', 'fieldFour', 'someNestedKey'];

setValue(obj, keysArr, 42);
console.log(obj);

Upvotes: 2

Matansh
Matansh

Reputation: 782

Yes you can!

var obj = {
 'fieldOne': {
    'fieldTwo': {
    'fieldThree': {
        'fieldFour': {
            'someNestedKey': 'test'
        }
    }
    }
 }
}

var keysArr = ['fieldOne', 'fieldTwo', 'fieldThree', 'fieldFour', 'value'];

var obj1 = obj;
for (var i = 0; i < keysArr.length - 1; i++) {
    if (obj1[keysArr[i]]) {
        obj1 = obj1[keysArr[i]];
    } else {
        break;
    }
}

obj1[Object.keys(obj1)[0]] = keysArr[keysArr.length - 1];

After executing this code, 'someNestedKey' will be set to 'value'.

Upvotes: 1

Related Questions