Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically updating a JavaScript object from a string path [duplicate]

Im trying to figure out if its possible to update a JavaScript object, using a string as the path.

In the example below, I'm trying to figure out how I can update the first books price using store>book>0>price as my path.

I know I can access this by writing data['store']['book'][0]['price'] but I need to be able to do this dynamically. Ive tried a few things but had no luck. Any Ideas?

This needs to work for any depth , not a fixed depth


Data:

 var data = { 
      "store": {
        "book": [ 
          { "category": "reference",
            "author": "Nigel Rees",
            "title": "Sayings of the Century",
            "price": 8.95
          },
          { "category": "fiction",
            "author": "Evelyn Waugh",
            "title": "Sword of Honour",
            "price": 12.99
          }
        ],
        "bicycle": {
          "color": "red",
          "price": 19.95
        }
      }
    }
var path = "store>book>0>price"

Function:

function updateObject(object, path, data) {
    var pathArray = path.split(">");
    // Some code here
} 
updateObject(data, path, "10.00");

Update

As felix pointed out the answer can be found here. Dynamic deep setting for a JavaScript object

Here is a working example for my scenario http://jsfiddle.net/blowsie/Sq8j3/9/

like image 902
Blowsie Avatar asked Feb 26 '13 15:02

Blowsie


3 Answers

function updateObject(object, newValue, path){

  var stack = path.split('>');

  while(stack.length>1){
    object = object[stack.shift()];
  }

  object[stack.shift()] = newValue;

}
like image 174
DanC Avatar answered Oct 06 '22 08:10

DanC


You want to update your method signature to accept the: object you're modifying, the path string, and the value you're assigning to the final path property.

function updateObject(data, path, value) {
        var pathArray = path.split(">");
        var pointer = data; // points to the current nested object
        for (var i = 0, len = pathArray.length; i < len; i++) {
            var path = pathArray[i];
            if (pointer.hasOwnProperty(path)) {
                if (i === len - 1) { // terminating condition
                    pointer[path] = value;
                } else {
                    pointer = pointer[path];
                }
            } else {
                // throw error or terminate. The path is incorrect
            }
        }
    }

Or recurse. Or use a while loop. But this is the general idea.

Fiddle: http://jsfiddle.net/Sq8j3/8/

like image 33
stinkycheeseman Avatar answered Oct 06 '22 08:10

stinkycheeseman


It's slightly confusing that you've called your object data but that data is also an argument of your function. I've changed the argument's name therefore to newVal in order to clear up this potential problem.

This loops through the path and constantly resets a variable called e which starts by pointing to the data object generally and gets more specific as we loop. At the end, you should have an almost reference to the exact property -- we use the last part of the path to set the new value.

function updateObject(newVal, path) {
    var pathArray = path.split(">"),
        i = 0,
        p = pathArray.length - 1, // one short of the full path
        e = data; // "import" object for changing (i.e., create local ref to it)
    for (i; i < p; i += 1) { // loop through path
        if (e.hasOwnProperty(pathArray[i])) { // check property exists
            e = e[pathArray[i]]; // update e reference point
        }
    }
    e[pathArray[i]] = newVal; // change the property at the location specified by path to the new value
};

You might need to add something to catch errors. I have put a check in with the hasOwnProperty() call but you might need something more elaborate than this.

UPDATE

Had made a silly mistake in the code before but it should be working now. As evidenced here.

like image 41
guypursey Avatar answered Oct 06 '22 09:10

guypursey