51

When working with plain JavaScript objects it's easy to change a deeply nested object property:

people.Thomas.nickname = "Mr. T";

But with Immutable I have to go through each property's ancestors before I have a new people object:

var thomas = peopleImmutable.get("Thomas");
var newThomas = thomas.set("nickname", "Mr .T");
peopleImmutable = peopleImmutable.set("Thomas", newThomas);

Is there a more elegant way to write this?

Matt Zeunert
  • 16,075
  • 6
  • 52
  • 78

1 Answers1

75

Maps in Immutable have a setIn method that makes it easy to set deep values:

peopleImmutable = peopleImmutable.setIn(["Thomas", "nickname"], "Mr. T");

Or, using split to generate the array:

peopleImmutable = peopleImmutable.setIn("Thomas.nickname".split("."), "Mr. T");
Matt Zeunert
  • 16,075
  • 6
  • 52
  • 78
  • How would you toggle a boolean using setIn? For example: peopleImmutable = peopleImmutable.setIn(["Thomas", hasNickName], toggleBooleanHere); – zero_cool Sep 10 '16 at 21:51
  • @zero_cool: I suppose peopleImmutable = peopleImmutable.setIn(["Thomas", "hasNickName"], !peopleImmutable.getIn(["Thomas", "hasNickName"]));` (untested) – Vincent Sels Sep 13 '16 at 14:38
  • @VincentSels This worked perfectly! What about changing all of the booleans in a deeply nested immutable object from false to true in one block? For example: options = fromJS({ one:{selected: false}, two: { selected: false} }). I'm in React, and trying to iterate through the object, and use setIn, but the state only gets set for the last key set. – zero_cool Sep 25 '16 at 19:23
  • 3
    Also check out the documentation for `update` and `updateIn` which instead of a `value` parameter takes a function parameter which passes the current value as an argument. So you could do something like `peopleImmutable.updateIn(["Thomas", "isAwesome"], value => !value)` – Nigh7Sh4de Oct 06 '16 at 13:45