Nested Sesssion Keys?


#1

Now technically I am using reactive dict but it uses the same core and session has the same issue. I am guessing there’s the chance I am missing something.

Is it not possible to handle nested keys? For example, I have data which mutates. I have multiple values that are categorized and I need to update just a small part of them with reactive capabilities. The “key” will change for some of them so I need to be able to capture all of them and parse through them to build react components.

kind: {
one: { … },
two: { … },
three: { … }
}

The problem is that using set will overwrite the entire thing and only the last one remains! Ah!

myDict = new ReactiveDict;
myDict.set({
     kind: {
          one: { foo: "bar" },
          two: { foo2: "bar2" },
          three: {food3: "bar3" }
     }
});

^ so that will set it up properly, great.but now I need to modify just ONE of those values:

myDict.set({kind: {one: {foo: "NewValue"}});

Now i’ve lost two and three!

I am fairly new to javascript coming from tcl / python which handle dicts like this so perhaps I am just using this wrong? With TCL here is how it would work as a reference:

set kind [dict create \
     one [dict create foo bar] \
     two [dict create foo2 bar2] \
     three [dict create foo3 bar3]
]

% kind {one {foo bar} two {foo2 bar2} three {foo3 bar3}

dict set kind one foo NewValue

% kind {one {foo NewValue} two {foo2 bar2} three {foo3 bar3}

#2

Just as a note, I did find that I could probably do something like query the value, edit it with a function then post it back as the full value. Seems slow and wasteful, but it should work… Something like

function set(v, path, value) {
    var schema = v;  // a moving reference to internal objects within obj
    var pList = path.split('.');
    var len = pList.length;
    for(var i = 0; i < len-1; i++) {
        var elem = pList[i];
        if( !schema[elem] ) schema[elem] = {}
        schema = schema[elem];
    }

    schema[pList[len-1]] = value;
    return v
}
myDict = new ReactiveDict;
myDict.set({
     kind: {
          one: {foo: "bar"},
          two: {foo2: "bar2"}
     }
});
var tempKind = myDict.get('kind');
var changedValue = set(tempKind, 'one.foo', "NewValue");
myDict.set('kind', changedValue);

All this just seems so hard to update specific values. Let me know if I am missing something! Thanks guys! New to all this but love Meteor so far - especially when combined with React!


#3

Reactive Dict (and Session) both treat objects in an unexpected way, in that they attempt to parse the object into individual key-value pairs. From the Session docs:

Session.set can also be called with an object of keys and values, which is equivalent to calling Session.set individually on each key/value pair.

This means that when you pass what you intend as a modification to your base object, what you instead do is cause the parse to run again (and “throw away” what it now doesn’t see).

You should probably be using Reactive Vars instead, which don’t mutate the supplied object. Then, you can do something like:

let myVar = new ReactiveVar({
  kind: {
    one: { foo: "bar" },
    two: { foo2: "bar2" },
    three: {food3: "bar3" }
  }
});

and then later, to update the object:

let temp = myVar.get();
temp.kind.one.foo = "NewValue";
myVar.set(temp);

which will preserve the other object properties.

Don’t forget to meteor add reactive-var to your project :smile:


#4