eselk
eselk

Reputation: 6894

knockoutjs mapping, add new item to child array without the extra mapping object

Using this test code, based on my real project:

var test = ko.mapping.fromJS({ id: 1, kids: [{ name: "sue"}] });
test.kids.push({ name: "tim" });
test.kids.push(ko.mapping.fromJS({ name: "joe" }));
console.log(test);
console.log(test.kids()[0]);
console.log(test.kids()[1]);
console.log(test.kids()[2]);
test.kids()[2].__ko_mapping__ = undefined;
console.log(test.kids()[2]);

The console output in Firebug shows:

Object { __ko-mapping__={...}, id=d(), kids=d() }
Object { name=d() }
Object { name="tim" }
Object { __ko-mapping__={...}, name=d() }
Object { name=d() }

My goal is to add items to the kids array after the initial mapping of the data, and have those items look identical to the original items added. If I just push an object directly on the array, the properties are not observables. If I push the object using ko.mapping.fromJS they get an extra __ko_mapping__ object included. I'd rather not have the extra object, as it doesn't seem to be needed (original items don't have it and work fine), and I might use this same design in places where I am adding 1000s of items later.

Setting the object to undefined does seem to remove the extra object, but would rather not have it created in the first place if possible.

Upvotes: 2

Views: 1251

Answers (3)

Guest
Guest

Reputation: 1

http://knockoutjs.com/documentation/plugins-mapping.html

You can choose which properties get mapped and how.

Upvotes: 0

eselk
eselk

Reputation: 6894

Based on lack of any other answers, and the only answer being one that is probably a better design practice but actually does the opposite of what I asked for (it adds a mapping object to every child).. I guess I already had the answer in my original question, just assumed there must be a better way.

So for future readers, here it is:

test.kids()[2].__ko_mapping__ = undefined;

Just set ko_mapping to undefined, if you want to get rid of it.

See the comments and other answer as to why this isn't a good idea in-general. For my needs, and maybe you have the same, it is a good idea.

Upvotes: 1

pcw216
pcw216

Reputation: 126

I generally find it useful to create a strong prototype for 'Kids' and tell the mapping plugin to use it when mapping your initial data. This would cause the contents of the array to be identical and have the added benefit of permitting computeds and observables for each Kid.

http://jsfiddle.net/Z9GF5/

var Kid = function(json){
    ko.mapping.fromJS(json, {}, this);
}

var mapping = {
    'kids': {
        create: function(options) {
            return new Kid(options.data);
        }
    }
}

Now if you have to add items just create new Kids.

var test = ko.mapping.fromJS({ id: 1, kids: [{ name: "sue"}] }, mapping);
test.kids.push(new Kid({ name: "tim" }));
test.kids.push(new Kid({ name: "joe" }));
console.log(test);
console.log(test.kids()[0]);
console.log(test.kids()[1]);
console.log(test.kids()[2]);

Firebug then shows:

Object {id: function, kids: function, __ko_mapping__: Object}
Kid {name: function, __ko_mapping__: Object}
Kid {name: function, __ko_mapping__: Object}
Kid {name: function, __ko_mapping__: Object}

Upvotes: 0

Related Questions