diff --git a/src/json/docs/component.json b/src/json/docs/component.json index 8ec0d80bd7e..2077cf35ec6 100644 --- a/src/json/docs/component.json +++ b/src/json/docs/component.json @@ -10,7 +10,7 @@ "examples": [ { - "name": "json_connect", + "name": "json-connect", "displayName": "JSON with Y.io", "description": "Use JSON to parse data received via XMLHttpRequest via Y.io calls — a simple JSON use case.", "modules": ["json"], @@ -20,7 +20,7 @@ }, { - "name": "json_freeze_thaw", + "name": "json-freeze-thaw", "displayName": "Rebuilding Class Instances from JSON Data", "description": "Use the replacer and reviver parameters to reconstitute object instances that have been serialized to JSON.", "modules": ["json"], @@ -30,7 +30,7 @@ }, { - "name": "json_convert_values", + "name": "json-convert-values", "displayName": "Adding New Object Members During Parsing", "description": "Use a currency conversion calculation to add a new price member to a JSON response, demonstrating how JSON data, once retrieved, can be transformed during parsing.", "modules": ["json"], diff --git a/src/json/docs/index.mustache b/src/json/docs/index.mustache old mode 100755 new mode 100644 diff --git a/src/json/docs/json-freeze-thaw.mustache b/src/json/docs/json-freeze-thaw.mustache new file mode 100644 index 00000000000..4105cc10190 --- /dev/null +++ b/src/json/docs/json-freeze-thaw.mustache @@ -0,0 +1,156 @@ +{{>json-freeze-thaw-css}} + +
+

This example illustrates one method of serializing and recreating class instances by using the `replacer` and `reviver` parameters to `JSON.stringify` and `JSON.parse` respectively.

+
+ +
+{{>json-freeze-thaw-markup}} +{{>json-freeze-thaw-js}} +
+ +

The CaveMan class

+

For this example, we'll use a class CaveMan, with a property `discovered` that holds a `Date` instance, and a method `getName`.

+ +``` +YUI().use("node", "json", function(Y) { + +function CaveMan(name,discovered) { + this.name = name; + this.discovered = discovered; +}; +CaveMan.prototype.getName = function () { + return this.name + ", the cave man"; +} + +... +``` + +

Add `freeze` and `thaw` static methods

+

We'll add the methods responsible for serializing and reconstituting instances to the CaveMan class as static methods.

+ +``` +// Static method to convert to a basic structure with a class identifier +CaveMan.freeze = function (cm) { + return { + _class : 'CaveMan', + n : cm.name, + d : cm.discovered // remains a Date for standard JSON serialization + }; +}; + +// Static method to reconstitute a CaveMan from the basic structure +CaveMan.thaw = function (o) { + return new CaveMan(o.n, o.d); +}; +``` + +

Reference the methods in replacer and reviver functions

+

We'll create an `example` namespace to hold our moving parts. In it, we'll add a method to pass to `JSON.stringify` that calls our custom serializer, and another method to pass to `JSON.parse` that detects the serialized structure and calls our thawing method.

+ +``` +var example = { + cryo : function (k,o) { + return (o instanceof CaveMan) ? CaveMan.freeze(o) : o; + }, + + revive : function (k,v) { + // Check for cavemen by the _class key + if (v instanceof Object && v._class == 'CaveMan') { + return CaveMan.thaw(v); + } + // default to returning the value unaltered + return v; + } +}; +``` + +

The data to be serialized

+

We'll create a CaveMan instance and nest it in another object structure to illustrate how the thawing process still operates normally for all other data.

+``` +example.data = { + count : 1, + type : 'Hominid', + specimen : [ + new CaveMan('Ed',new Date(1946,6,6)) + ] +}; +``` + +

Thawing from the inside out and the `Date` instance

+

The reviver function passed to `JSON.parse` is applied to all key:value pairs in the raw parsed object from the deepest keys to the highest level. In our case, this means that the `name` and `discovered` properties will be passed through the reviver, and then the object containing those keys will be passed through.

+

We'll take advantage of this by watching for UTC formatted date strings (the default JSON serialization for Dates) and reviving them into proper `Date` instances before the containing object gets its turn in the reviver.

+ +``` +var example = { + dateRE : /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d+)?Z$/, + + cryo : function (k,o) { + return (o instanceof CaveMan) ? CaveMan.freeze(o) : o; + }, + revive : function (k,v) { + // Turn anything that looks like a UTC date string into a Date instance + var match = Y.Lang.isString(v) ? v.match(example.dateRE) : null, + d; + + if (match) { + d = new Date(); + d.setUTCFullYear(match[1], (match[2] - 1), match[3]); + d.setUTCHours(match[4], match[5], match[6]); + return d; + } + // Check for cavemen by the _class key + if (v instanceof Object && v._class == 'CaveMan') { + return CaveMan.thaw(v); + } + // default to returning the value unaltered + return v; + } +}; +``` + +

Now when the reviver function is evaluating the object it determines to be a CaveMan, the `discovered` property is correctly containing a `Date` instance.

+ +

Choose your serialization

+

You'll note there are two freeze and thaw operations going on in this example. One for our CaveMan class and one for `Date` instances. Their respective serialization and recreation techniques are very different. You are free to decide the serialized format of your objects. Choose whatever makes sense for your application.

+

Note: There is no explicit `Date` serialization method listed inline because `JSON` natively supports `Date` serialization. However, it is outside the scope of the parser's duty to create Date instances, so it's up to you to recreate them in the `parse` phase. Feel free to use the method included here.

+ +

Show and Tell

+

Now we add the event handlers to the example buttons to call `JSON.stringify` and `parse` with our `example.cryo` and `example.revive` methods, respectively.

+ +``` +Y.one('#demo_freeze').on('click',function (e) { + example.jsonString = Y.JSON.stringify(example.data, example.cryo); + + Y.one('#demo_frozen').set('innerHTML', example.jsonString); + Y.one('#demo_thaw').set('disabled',false); +}); + +Y.one('#demo_thaw').on('click',function (e) { + var x = Y.JSON.parse(example.jsonString, example.revive); + cm = x.specimen[0]; + + Y.one('#demo_thawed').set('innerHTML', + "

Specimen count: " + x.count + "

"+ + "

Specimen type: " + x.type + "

"+ + "

Instanceof CaveMan: " + (cm instanceof CaveMan) + "

"+ + "

Name: " + cm.getName() + "

"+ + "

Discovered: " + cm.discovered + "

"); +}); + +}); // end of YUI(..).use(.., function (Y) { +``` + +

Full Code Listing

+ +``` +{{>json-freeze-thaw-css}} +``` + +``` +{{>json-freeze-thaw-markup}} +``` + +``` +{{>json-freeze-thaw-js}} +``` diff --git a/src/json/docs/partials/json-freeze-thaw-css.mustache b/src/json/docs/partials/json-freeze-thaw-css.mustache new file mode 100644 index 00000000000..48ad64e78b2 --- /dev/null +++ b/src/json/docs/partials/json-freeze-thaw-css.mustache @@ -0,0 +1,10 @@ + diff --git a/src/json/docs/partials/json-freeze-thaw-js.mustache b/src/json/docs/partials/json-freeze-thaw-js.mustache new file mode 100644 index 00000000000..8759327af4a --- /dev/null +++ b/src/json/docs/partials/json-freeze-thaw-js.mustache @@ -0,0 +1,87 @@ + diff --git a/src/json/docs/partials/json-freeze-thaw-markup.mustache b/src/json/docs/partials/json-freeze-thaw-markup.mustache new file mode 100644 index 00000000000..d004ad8c870 --- /dev/null +++ b/src/json/docs/partials/json-freeze-thaw-markup.mustache @@ -0,0 +1,6 @@ +
+ + +
(stringify results here)
+
+