JSON Manager - Documentation

Purpose

Middleware plugin that perform JSON manipulation through patches and are accessed through dataset, a named alias.

Use when

When a reteived JSON file or when a JSON result requested through a RESTful API need a few minor manipulation in order to be displayed with the data-json.

Do not use when

To perform complexe manipulation or metamorphing data in a way that change his original meaning. By complexe manipulation is like filtering, sorting, forking, merging, infering a result based from multiple source inside or outside the data context and any other operation that take time or required considerable amount of ressource where it badly impact the performance of the device and the user experience.

Instead, if your JSON file need a lot of manipulation, consider to create your own RESTful service that will accomodate for performing those task and it will allow to cache the result.

Instead, if your are metamorphing the JSON data source, then that is probably means it should be an middleware service that do that transformation prior to receive the data for being display.

Working example

English:

French:

How to implement

JSON manager is a middleware plugin that allow to manipulate JSON data and return it as a fetch result.

  1. From a plugin that request JSON content, refer to a dataset name in the request url. For example with the data json plugin.

    <span data-json-replace="#[example1]/product">unknown number of</span>
  2. Create a JSON manager plugin by adding the attribute data-jsonmanager to an element. At the minimum, you will need to configure the url and the dataset name.

    Then the following configuration is required if:

    • patches=[] If you are only applying static patches at the fetched JSON.

      <div data-wb-jsonmanager='{
      		"url": "demo/data-en.json",
      		"name": "example1",
      		"patches": [
      			{ "op": "wb-count", "path": "/products", "set": "/nbproduct" },
      			{ "op": "copy", "from": "/products/0", "path": "/product"}
      		]
      	}'></div>
    • wait=true If the JSON manager need to wait to receive patches from another plugin, like urlmapping. Note that in this mode you can also specified a series of default patches to apply through setting the configuration patches

      <div id="jmexample1" data-wb-jsonmanager='{
      			"url": "data/data-1.json",
      			"name": "example1",
      			"wait": true
      		}'></div>

  3. Configure your patches as per the supported operation bellow

Note: The json manager can not be set on the same element that listen to wb.jsonfetch event, like data json.

Using Dataset

To refer at a dataset, it is quite similar to a JSON pointer. But you start with a bracket "[", followed by the dataset name, then by the closing bracket "]" and the rest is the JSON pointer to navigate in the dataset. You can find read about JSON Pointer in the RFC6901 spec or in the data-json plugin documentation.

#[DatasetName]/JSON/Pointer

JSON patches operation

JSON operation is defined as per RFC6002 - JavaScript Object Notation (JSON) Patch with additional operation to fullfill the needs of the JSON manager. Described in the documentation, the following operation are supported: add, remove, replace, move, copy, test, wb-count, wb-first, wb-last, wb-toDateISO and wb-toDateTimeISO. The operation that start with "wb" are custom operation defined inside the JSON manager

In the description bellow when it refering to :

<path>
That represents a string containing a valid JavaScript Object Notation (JSON) Pointer [RFC6901]. You can find JSON pointer example in the data-json working example under "Selecting data" heading.
<value>
A valid value, it could be a number, a string, a JSON object or a JSON array.

You will find a few examples in the Appendix A of RFC6002

Operation Syntax What it's does
Add { "op": "add", "path": <path>, "value": <value> }

Performs one of the following functions, depending upon what the target location references:

  • If the target location specifies an array index, a new value is inserted into the array at the specified index.
  • If the target location specifies an object member that does not already exist, a new member is added to the object.
  • If the target location specifies an object member that does exist, that member's value is replaced.

For adding in an array, you may finish the path by "/0" to prepend and "/-" to append the value.

Remove { "op": "remove", "path": <path> } Removes the value at the target location.
Replace { "op": "replace", "path": <path>", "path": <value> } Replaces the value at the target location with a new value.
Move { "op": "move", "from": <path>, "path": <path> } Removes the value at a specified location and adds it to the target location.
Copy { "op": copy, "from": <path>, "path": <path> } Copies the value at a specified location to the target location.
Test { "op": "test", "path": <path>, "value": <value> }

Tests that a value at the target location is equal to a specified value. On failing, it would result in no changes being made.

Note by using test operation, it makes the pathes atomic. So that means that is one test operation fail, nothing will be executed otherwise all operation get executed. The execution of any test operation are prioritized before any other operation.

Counting items { "op": "wb-count", "path": <path>, "set": <path> }

Count the number of items in an array and copy the value at a specified location.

Filter can be used to count a specific subset.

Counting items with filter { "op": "wb-count", "path": <path>, "set": <path>, "filter": <evaluation object>, "filternot": <evaluation object> }

Both attribute filter and filternot are optional. They will contain an array of "evaluation object" or one evaluation object defined in the filtering sub section of "Configuration options" bellow.

First item { "op": "wb-first", "path": <path>, "set": <path> } Copy the first item from an array at a specified location.
Last item { "op": "wb-last", "path": <path>, "set": <path> } Copy the last item from an array at a specified location.
Formatting a number { "op": "wb-nbtolocal", "path": <path> }

Replace the number at the <path> location that represents the number value formatted according to the conventions of the host environment's current locale.

Additional setting:

locale
Default is the current page language. You can set any valid locale, except IE only support "en" and "fr" locale. { "op": "wb-nbtolocal", "path": <path> "locale": "fr-CA" }
prefix
Default: empty string. This prepend a string before the formatted number. { "op": "wb-nbtolocal", "path": <path> "suffix": "$CAN " }
suffix
Default: empty string. This append a string after the formatted number. { "op": "wb-nbtolocal", "path": <path> "suffix": "$ CAN" }
Formating a date to ISO (YYYY-MM-DD) { "op": "wb-toDateISO", "path": <path> }
or
{ "op": "wb-toDateISO", "path": <path>, "set": <path> }
Format a date value to data ISO and copy the value at a specified location. If set is not defined, it will be the value located at path that will be replaced.
Formating a date and time to ISO (YYYY-MM-DD HH:MM) { "op": "wb-toDateTimeISO", "path": <path> }
or
{ "op": "wb-toDateTimeISO", "path": <path>, "set": <path> }
Format a date value to date time ISO and copy the value at a specified location. If set is not defined, it will be the value located at path that will be replaced.

It's is possible to add your own custom operations, like:

window[ "wb-jsonmanager" ] = {
	ops: [
		{
			name: "wb-count",
			fn: function( obj, key, tree ) {
				var countme = obj[ key ],
					len = 0;
				if ( $.isArray( countme ) ) {
					len = countme.length;
				}

				jsonpatch.apply( tree, [
					{ op: "add", path: this.set, value: len }
				] );
			}
		},
		{
			name: "wb-first",
			fn: function( obj, key, tree ) {
				var currObj = obj[ key ];
				if ( !$.isArray( currObj ) || currObj.length === 0 ) {
					return;
				}

				jsonpatch.apply( tree, [
					{ op: "add", path: this.set, value: currObj[ 0 ] }
				] );
			}
		}
	],
	opsArray: [ ],
	opsRoot: [ ],
}

There is tree type of configuration where you can defined your custom operation depending on what the operation is executed.

ops
Basic operation on a JSON node.
opsArray
Operation made upon JSON array.
opsRoot
Operation that target the root of JSON object.

Debugging

You can set the configuration option "debug": true to show, added the element that call the JSON manager, the modified JSON object and his applied patches. The JSON are displayed without any formating.

<div data-wb-jsonmanager='{
	"url": "data-en.json",
	"name": "example2",
	"debug": true
}'></div>

Cache busting

Before to use the cache busting mechanism with your data json instance, it's highly recommended to configure your server properly instead.

Various strategy can be set on the server side and those are communicated to the browser through an http header as defined in section 5 of RFC7234.

Configuration options

Option Description How to configure Values
url Required. Define the url or the dataset name to use. When used in a template mode, the URL should point to an array object. You can follow the url or the dataset name by a JSON Pointer (RFC6901).
data-wb-jsonmanager='{ "url": "location/of/json/file.json#/" }'
The url are a json file
data-wb-jsonmanager='{ "url": "[datasetName]#/" }'
The url is a reference to a dataset managed by a json-manager defined in the same page
name Required. The dataset name that other plugin will be able to use as an alias to a JSON file. data-wb-jsonmanager='{ "url": "", "name": "ADataSetName" }' String
wait Indicate if plugins that use the named dataset should wait to display information until all patches is received. data-wb-jsonmanager='{ "url": "", "name": "ADataSetName", "wait": true }' Boolean
false (default)
Will execute the patches when the plugin is initialized
true
Will wait to notify plugins that use the named dataset, until patches is received throught the event patches.wb-jsonmanager.
patches Array of patches, operation object, to be applied to the JSON data-wb-jsonmanager='{ "url": "", "name": "ADataSetName", "patches": [ {operation object} ] }' Array of operation object or a unique operation object
{Operation object} Object structured as per RFC6002 specification. data-wb-jsonmanager='{ "url": "", "name": "ADataSetName", "patches": [ { "op": "Name of the operation", (any additional parameter as per the operation) } ] }' See section 4 of RFC6902. All the supported operation is defined above in the section JSON patches operation.
wraproot Name of a property where to move the JSON root into. data-wb-jsonmanager='{ "url": "", "name": "ADataSetName", "wraproot": "root" }'
false (default)
Keep the JSON as it
String
Will create a new property, as named by the string value, then move the root into that property.
filter Available for when selecting array only. Item that is true will be kept and item that is false will be removed. data-wb-jsonmanager='{ "url": "", "filter": [ {evaluation object} ] }'

Evaluation object have the following property

path
Required. JSON pointer to the data being evaluated
value
Required. Value of witch the data would be evaluated
optional
Indicated if the evaluation is optional.

There is more details in the filter section bellow

filternot Available for when selecting array only. Item that is true will be removed and item that is false will be kept. This filter happen after the configuration for the "filter" option has been evaluated. data-wb-jsonmanager='{ "url": "", "filternot": [ {evaluation object} ] }'

Evaluation object have the following property

path
Required. JSON pointer to the data being evaluated
value
Required. Value of witch the data would be evaluated
optional
Indicated if the evaluation is optional.

There is more details in the filter section bellow

debug Show the modified JSON object and his applied patches after there are applied. data-wb-jsonmanager='{ "url": "", "name": "ADataSetName", "wraproot": "root" }' Boolean
false (default)
There is no debug info that is displayed
true
Will display a unformated result.
nocache Prevent caching. Prior using the functionality, use the various caching strategies that can be set and communicated through http header from your server, as defined in section 5 of RFC7234. Also, please note that some server may not like to have an query appended to his url and you may get an HTTP error like "400 Bad Request" or "404 Not Found". Like a page served by a domino server will return 404 error if the query string do not start with "?open", "?openDocument" or "?readForm". data-wb-json='{ "url": "", "nocache": true }' or data-wb-json='{ "url": "", "nocache": "nocache" }'
Default
The browser will manage the cache based on how the server has sent the file.
true
Boolean, Use the same cache buster id for the user session. Clossing and opening the tab should generate a new cache busting id.
nocache
String, A new id is generated everytime the file is fetched
nocachekey Prevent caching. Optional, it defined what query parameter name to use for the cache busting. data-wb-json='{ "url": "", "nocache": true, "nocachekey": "wbCacheBust" }'
Default
Will use "wbCacheBust" for the parameter name.
String
URL pre-encoded string

Filtering (evaluation object)

The path selector must point to an valid JSON array object. All the option presented in the table bellow can be combined.

Option How to configure Values and clarification
path { "filter": [ { "path": "/JSON Pointer" } ] …} or { "filternot": [ { "path": "/JSON Pointer" } ] …} A valid JSON Pointer (RFC6901) to the data being evaluated.. It's must start with an "/".
value { "filter": [ { "value": "A value" } ] …} or { "filternot": [ { "value": "A value" } ] …} Any value that could be compared with the information retreived form the path. An exact match is performed.
optional { "filter": [ { "optional": true } ] …}' or { "filternot": [ { "optional": true } ] …}' True or false. If omited it will be false by default.

Events

Event Trigger What it does
patches.wb-jsonmanager

Triggered manually via javascript or automatically via other plugin that interact with the JSON manager.

$( "#MyJsonManager" ).trigger(  {
	type: "patches.wb-jsonmanager",
	patches: [ { JSON patached operation object } ]
} );

Where supporting the following event property:

patches
(Required) Array of or a single JSON patches operation.
cumulative
Boolean. Default (false) If true the patches applied for this one event will be cumulative and impact subsequent applied patches.
Apply patches to the dataset and will send a request to update the content of all plugin that are binded to this dataset.
postpone.wb-jsonmanager Triggered automatically by the json fetch plugin to let the JSON manager that other plugin depends on it. Postpone the json fetch call until the dataset is ready.
wb-init.wb-jsonmanager Triggered manually (e.g., $( ".wb-jsonmanager" ).trigger( "wb-init.wb-jsonmanager" );). Used to manually initialize the wb-jsonmanager plugin. Note: The wb-jsonmanager plugin will be initialized automatically unless the required markup is added after the page has already loaded.
wb-init.wb-jsonmanager Triggered manually (e.g., $( ".wb-jsonmanager" ).trigger( "wb-init.wb-jsonmanager" );). Used to manually initialize the wb-jsonmanager plugin. Note: The wb-jsonmanager plugin will be initialized automatically unless the required markup is added after the page has already loaded.
wb-ready.wb-jsonmanager Triggered automatically after an wb-jsonmanager is initialized. Used to identify when an wb-jsonmanager has initialized (target of the event)
$( document ).on( "wb-ready.wb-jsonmanager", ".wb-jsonmanager", function( event ) {
});
$( ".wb-jsonmanager" ).on( "wb-ready.wb-jsonmanager", function( event ) {
});
wb-ready.wb Triggered automatically when WET has finished loading and executing. Used to identify when all WET plugins and polyfills have finished loading and executing.
$( document ).on( "wb-ready.wb", function( event ) {
});

Source code

JSON manager plugin source code on GitHub

Date modified: