Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ko.toJSON is creating some unwanted copiedProperties properties

Tags:

knockout.js

I'm findign that ko.toJSON is creating some unwanted stuff like:

copiedProperties destroy

{"test":1,"AppStart":true,"requestedDateFormat":"YYYY-MM-DD","__ko_mapping__":{"ignore":[],"include":["_destroy"],"copy":[],"observe":[],"mappedProperties":{"test":true,"AppStart":true,"requestedDateFormat":true},"copiedProperties":{}}}

whats the point of these? can I remove them by default?

like image 829
FutuToad Avatar asked Mar 08 '13 18:03

FutuToad


2 Answers

If you are using the KO mapping plugin you should use the plugin's conversion methods e.g.

ko.mapping.toJSON

and ko.mapping.toJS

instead of the built in ko.toJSON and ko.toJS.

Because the mapping version of the methods will take of the additional properties which by the way are used internally by the plugin itself.

Demo JSFiddle.

like image 80
nemesv Avatar answered Nov 24 '22 07:11

nemesv


If your model is a 'hybrid' model that hasn't completely been created using the mapping plugin then using ko.mapping.toJSON may not remove the __ko_mapping__ properties you're expecting.

By 'hybrid' model I mean one you've created as a normal object and then mapped only portions into it with the mapping plugin.

The easiest solution is to add the following to each 'class' that is ending up with the unwanted properties. This will remove it whether you use mapping.toJSON or ko.toJSON.

    Product.prototype.toJSON = function()
    {
        var copy = ko.toJS(this);

        delete (copy.__ko_mapping__);

        return copy;
    }

This method is described in Controlling How an Object Is Converted to JSON although not in connection to the mapping plugin.


Example:

Here's some JSON that ended up with unwanted mapping when it was serialized (even with ko.mapping.toJSON).

I just added the above code to the 'product' class (I'm using typescript so I'm calling them classes).

{"sku":"3007","total":0,"desc":"Description","qty":0,"each":null,"dirty":false,"removePending":false,"editableQty":0,"itemUpdating":false,"__ko_mapping__":{"ignore":[],"include":["_destroy"],"copy":[],"observe":[],"mappedProperties":{"sku":true,"qty":true},"copiedProperties":{}}},{"sku":"3008","total":0,"desc":"Description","qty":0,"each":null,"dirty":false,"removePending":false,"editableQty":0,"itemUpdating":false,"__ko_mapping__":{"ignore":[],"include":["_destroy"],"copy":[],"observe":[],"mappedProperties":{"sku":true,"qty":true},"copiedProperties":{}}},

Afterwards I got this much cleaner JSON. I'm now going to go back and delete(copy.removePending) and delete(copy.itemUpdating) which are view model only.

{"sku":"3007","total":0,"desc":"Description","qty":0,"each":null,"dirty":false,"removePending":false,"editableQty":0,"itemUpdating":false},{"sku":"3008","total":0,"desc":"Description","qty":0,"each":null,"dirty":false,"removePending":false,"editableQty":0,"itemUpdating":false},


Also please note that calling the mapping version of toJSON internally just calls JSON.stringify(ko.mapping.toJS(object)). In other words ko.mapping.toJSON is a convenience function and does not do its own stringification.

// from mapping source code
exports.toJSON = function (rootObject, options)
{
    var plainJavaScriptObject = exports.toJS(rootObject, options);
    return ko.utils.stringifyJson(plainJavaScriptObject);
};

// from main knockout source code for `ko.utils`
stringifyJson: function (data, replacer, space) {   // replacer and space are optional
    if (!JSON || !JSON.stringify)
        throw new Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
    return JSON.stringify(ko.utils.unwrapObservable(data), replacer, space);
},
like image 29
Simon_Weaver Avatar answered Nov 24 '22 08:11

Simon_Weaver