1

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.

Prozrachniy
  • 151
  • 8

4 Answers4

2

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);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • I guess you can check for index, if its last and set value accordingly. `.slice` would cause extra iterations – Rajesh Apr 05 '17 at 09:46
  • it think it's better not to mutate the given data, beside the object. – Nina Scholz Apr 05 '17 at 09:48
  • I think I choose my words incorrectly. I meant, you are slicing and popping path array. Instead of these action, you can just check in `.reduce` if its the last iteration and if it is, set value to the key. I tried the same in my answer. – Rajesh Apr 05 '17 at 09:51
  • 1
    you could do it (obviously), but another check spoils the simplicity of the callback. – Nina Scholz Apr 05 '17 at 09:53
1

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'.

Matansh
  • 764
  • 4
  • 13
1

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");
dev8080
  • 3,950
  • 1
  • 12
  • 18
1

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)
Community
  • 1
  • 1
Rajesh
  • 24,354
  • 5
  • 48
  • 79