2

I'm trying to access a property of an object dynamically with a string. For example: ".id.public" -> anyObject["id"]["public"]

The problem - I don't know how many arguments I have (for example ".id" or ".id.public" or ".id.public.whatever".

I made a little workaround:

var currentSplit = anyObject;
var splitted = "id.public".split("\.");
splitted.forEach(function(s) { currentSplit = currentSplit[s]; });

When I try now to override the object property I will override the reference and not the object property.

currentSplit = "test";

I tried already stuff like anyObject["id.public"] = "test"; but it didn't work.

  • You can't access nested object properties with a string in javascript, you need some sort of helper function to do it for you, you could look at angulars `$parse` interface for some inspiration. – Willem D'Haeseleer Aug 14 '14 at 11:14
  • Two variables that share the same value doesn't mean you can change both variables by just assigning one. Do you intend to read a value at "id.public", or to write a value at "id.public" ? Does [this answer](http://stackoverflow.com/a/6394168/2191722) work for you ? – Volune Aug 14 '14 at 11:18

3 Answers3

2

The deep-get-set library does what you want:

function get (obj, path) {
  var keys = path.split('.');
  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    if (!obj || !hasOwnProperty.call(obj, key)) {
      obj = undefined;
      break;
    }
    obj = obj[key];
  }
  return obj;
}

function set (obj, path, value) {
  var keys = path.split('.');
  for (var i = 0; i < keys.length - 1; i++) {
    var key = keys[i];
    if (deep.p && !hasOwnProperty.call(obj, key)) obj[key] = {};
    obj = obj[key];
  }
  obj[keys[i]] = value;
  return value;
}
Volune
  • 4,324
  • 22
  • 23
  • Personally I would avoid the names `get` and `set` because they can be operators by themselves; but otherwise this looks fine – Paul S. Aug 14 '14 at 11:29
  • Same for me, I just copied code from the library, in which ```set``` and ```get``` are locally defined and not exposed. – Volune Aug 14 '14 at 11:33
  • I think my solution is better, it does it in one ultra fast function and it does a lot more, it can even execute a method and walk any object that method returns, a lot smarter in one tiny box! – MartinWebb Aug 14 '14 at 11:34
1

Yet another way for setting value

function setVal(obj, path, val){
    var paths = path.split('.'),
        curProp = obj;

    for(var i=0;i<paths.length-1;i++){
        curProp = curProp[paths[i]];
    }
    curProp[paths[i]] = val;

}

and use it like

setVal(anyObj, "id.public", 'newValue');
Grundy
  • 13,356
  • 3
  • 35
  • 55
0

You can't do that without the help of a little code like this:

 var mapToProperty = function(obj, path, value) {
        if (!path) return obj;

        var parts = path.split("."),
           p = parts[0],
           v = (typeof obj[p] === "function") ? obj[p](value) : (parts.length !==1 || !value) ? obj[p] : (obj[p] = value), value ;
           if (parts.length == 1) return v;
               return mapToProperty(v, parts.slice(1).join("."), value);
}

// use it like this

var myvalue = mapToProperty(myObj, "address.street")

// you can map into your objects as far as you want. obj1.obj2.obj3.prop

// you can set as well :-)

mapToProperty(myObj, "address.street", "This is great!")
MartinWebb
  • 1,998
  • 1
  • 13
  • 15
  • `ReferenceError: func is not defined`, also, where does it set `value`? – Paul S. Aug 14 '14 at 11:18
  • This function will also execute methods - for example pass it an object with a method that evaluates to something obj1.method() – MartinWebb Aug 14 '14 at 11:18
  • Sorry copied from my libary missed that erorr, fixed. – MartinWebb Aug 14 '14 at 11:19
  • pass the value in as per the paramters, obj, stringmap, value – MartinWebb Aug 14 '14 at 11:19
  • I don't see a line like `obj[p] = value;` so when I try `o = {a:{b:''}}; mapToProperty(o, 'a.b', 'foo');` with your code, I get `o.a.b; // still ""` – Paul S. Aug 14 '14 at 11:21
  • 1
    OK, sorry this sets on methods, it is the way it was intended I can modify it so that it sets properties if a value is passed give me 5! – MartinWebb Aug 14 '14 at 11:24
  • OK it has been updated, I have not tested it thoroughly but it should work fine. – MartinWebb Aug 14 '14 at 11:27
  • This function does a number of things, it executes methods, walks down and object, returns the value or sets and returns it. For example if a method returns an object, it will walk that object too. And its fast! – MartinWebb Aug 14 '14 at 11:29
  • Tried ```var a = {}; mapToProperty(a, 'b.c.d', 2);```, got ```{"b":2}``` – Volune Aug 14 '14 at 11:45
  • The Question was to access an object with a map "property.anotherproperty" my function did just that, i pointed out it also set values, but made a mistake as it is part of my libary and in my uses case it sets into methods, I offered to change it on the fly, but as i have a day job that was on the fly, the change did not work correctly, I will change it shortly and update so it does all. But it did do what was asked, and it did it well, my mistake over offered. – MartinWebb Aug 14 '14 at 11:58
  • I have updated the code, this issues with deep setting on non method properties has been fixed, this was not a bug, I adapted the code by request live. – MartinWebb Aug 14 '14 at 12:11