diff --git a/lib/underscore-keypath.js b/lib/underscore-keypath.js index 970c4fb..deea28c 100644 --- a/lib/underscore-keypath.js +++ b/lib/underscore-keypath.js @@ -212,16 +212,32 @@ setValueForKeyPath : function (obj, keypath, newValue) { "use strict"; + + var createTarget = function( obj, segments ) { + var i, target; + for( i = 0; i < segments.length; i += 1 ) { + if( underscore.hasKeyPath( obj, segments.slice( 0, i + 1 ) ) ) { + continue; + } + if( i === 0 ) { + setProperty(obj, segments[ 0 ], {} ); + continue; + } + target = underscore.valueForKeyPath( obj, segments.slice( 0, i ) ); + setProperty(target, segments[ i ], {} ); + } + }; + var segments = toSegments(keypath), lastPropertyName, target; lastPropertyName = segments.pop(); - target = underscore(obj).valueForKeyPath(segments.join(".")); - - if (target !== null && target !== undefined) { - return setProperty(target, lastPropertyName, newValue); + target = underscore(obj).valueForKeyPath(segments); + + if (target === null || target === undefined) { + createTarget( obj, segments ); + target = underscore(obj).valueForKeyPath(segments); } - - return undefined; + return setProperty(target, lastPropertyName, newValue); }, pluckByKeyPath : function (array, keypath) { diff --git a/test/setValueForKeyPath.js b/test/setValueForKeyPath.js index f59dda1..d5f1fbf 100644 --- a/test/setValueForKeyPath.js +++ b/test/setValueForKeyPath.js @@ -40,4 +40,41 @@ describe("setValueForKeyPath", function () { fixture.bar._age.should.be.exactly(99); }); }); + + describe("set property when target missing", function () { + it("new path two deep must work", function () { + _(fixture).setValueForKeyPath("a.b", 2) + .should.be.exactly(2); + fixture.a.b.should.be.exactly(2); + }); + + it("new path three deep must work", function () { + _(fixture).setValueForKeyPath("c.d.e", 3) + .should.be.exactly(3); + fixture.c.d.e.should.be.exactly(3); + }); + + it("new path four deep must work", function () { + _(fixture).setValueForKeyPath("f.g.h.i", 4) + .should.be.exactly(4); + fixture.f.g.h.i.should.be.exactly(4); + }); + + it("new path three deep, down one must work", function () { + _(fixture).setValueForKeyPath("a.m.x", 5); + _(fixture).setValueForKeyPath("a.m.n.o", 5) + .should.be.exactly(5); + fixture.a.m.n.o.should.be.exactly(5); + }); + + it("new path three deep, down two must work", function () { + _(fixture).setValueForKeyPath("a.m.p.x", 5); + _(fixture).setValueForKeyPath("a.m.p.q.r", 6) + .should.be.exactly(6); + fixture.a.m.p.q.r.should.be.exactly(6); + }); + + }); + + });