When preparing your data to be sent back to the server, typically you will call
ko.toJSON on your view model or at least part of your view model. This first calls
ko.toJS to give you a clean copy of your objects with all observables unwrapped into plain properties. Then it converts this clean object into JSON using
JSON.stringify, which is implemented natively by your browser (or with a library like json2.js for older browsers).
However, it is not uncommon for your objects to contain computed observables or other observables that aren’t meant to go back to the server. Maybe your server-side framework can’t handle the extra properties or you don’t want to wastefully send the extra bytes on the wire. In some cases you might even have a child with a reference to its parent, which creates a circular reference that causes problems in the conversion to JSON.
While you could walk your object tree and delete any unwanted properties, there is actually an easier way.
JSON.stringify will check if each object has a
toJSON method and execute it first before serializing the object to its JSON representation. The name of the function “toJSON” is a bit misleading, as the function should return an object that is ready to be serialized into JSON, not your own attempt at a JSON string representing the object.
Suppose that you are constructing a simple Person object that looks like:
1 2 3 4 5 6 7
When you call
ko.toJSON on an object like this you will get:
Maybe your server-side code is not expecting the
full property or you just want to avoid sending it to be efficient. To control which properties are actually serialized, you can implement a
toJSON function for your object. It could look something like:
1 2 3 4 5
There are certainly many ways that you could implement this function, but the main objective is to return a version of the object that is ready to serialized. Now, your JSON would look like:
What if you would prefer to only send back the full name? Suppose that you have an array of Person objects and in JSON you want to convert it to an array of strings containing just the full names. In that case you could implement
1 2 3
unwrapObservable, because if this happens to get called as part of
ko.toJSON, then all of the observables would already be plain properties. This way we are flexible enough to handle it either way. If we had an array of Person objects, when converted to JSON they would look like:
Now, we have just an array of strings (no property names) to send to the server.
Here is a live sample:
toJSON function for your objects can be a nice way to avoid manually mapping your view model. You can easily transform your data into whatever format is most suitable to be sent to your server.