Skip to main content

Loading & Saving Data

Getting data into and out of the Toolkit is easy.

Node, Edge and Port Data#

Before we start, a quick note about what happens to the data you load.


When you load a Node such as this:

{ "id":"123", "name":"Foo", "aValue":567 }

This JSON object is available on the resulting Node instance as the data variable. This object is also what is passed to the templating code. So this snippet of code would get you the Node that was loaded and then access aValue on the Node's data:

var node = toolkitInstance.getNode("123");console.log(;--> 567


Ports are also backed with data. Consider a table in a Database Visualizer: in the Toolkit's example, we model a table as a Node, and each of the table's columns are Ports. Each column - each Port - has its own specific data such as ID, datatype, etc.

The loaders for the default JSON schemes add Nodes and Edges to the Toolkit. An example Node from the Database Visualizer is this:

{  "id":"book",  "name":"Book",  "type":"table",  "columns":[    { "id":"id", "datatype":"integer", "primaryKey":true },    { "id":"isbn", "datatype":"varchar" },    { "id":"title", "datatype":"varchar" }  ]}

The Database Visualizer's specifies columns as its port data property, which in this case has three entries. So the backing data for this first Port is:

{ "id":"id", "datatype":"integer", "primaryKey":true }


Edges also support the concept of being backed with data, but for Edges the Toolkit does not take the top-level JSON object - instead, it looks for a data member, eg:

edges:[  { source:1, target:2, data:{ id:"edgeFu", name:"An Edge", aValue:"I am an edge" } }  ...]

The data object is what is passed to the jsPlumb code that binds edge definitions from the model to actual jsPlumb Connections. Here is the equivalent code to the snippet given for Nodes above:

var edge = toolkitInstance.getEdge("edgeFu");console.log(;--> "I am an edge"


To load data into an instance of the Toolkit, use the load method. You can load data from a remote source - using ajax - or directly from an object in memory. Note that this is an incremental load: the existing data is not cleared when you call load. If you wish to replace the entire dataset, first call the clear() method.

Loading data via ajax#

toolkitInstance.load({  type:"json",  url:"someUrl.json",  onload:function() {                    // called after the data has loaded.      }});

Specifying HTTP Headers#

By default, the Toolkit will set the HTTP header Accept to the value application/json. You can override this by providing your own HTTP headers in the load call:

toolkitInstance.load({  type:"xml",  url:"someUrl.xml",  headers:{    Accept:"text/xml",    X-My-Header:"FOO"  },  onload:function() {                    // called after the data has loaded.      }});

Note: if you provide headers you must set an Accept header (if you want it to be set), because the Toolkit will not write a value for Accept into an HTTP headers object that does not have it.

Loading data from memory#

toolkitInstance.load({  type:"json",  data:{    nodes:[      { id:"foo", value1:"foo", value2:34 },      { id:"bar", value1:"bar", value2:24 }    ],    edges:[      { source:"foo", target:"bar", data: { value1:89 } }    ]});

Note that load returns the Toolkit instance, so in the case of loading data from memory you can chain methods that operate on the Toolkit:

toolkitInstance.load({  type:"json",  data: { some data }}).render(someElement, {  layout:{    type:"hierarchical"  }});

Appending Data#

Data can be appended via the load method, since it does not cause the underlying Graph to be cleared.

Data Formats#

The Toolkit ships with support for two JSON formats for loading and saving data. Should you need to, you can create custom load/save handlers for your own syntax.

Graph JSON Syntax#

This JSON syntax - the default - consists of a JSON object with an array for nodes, edges and ports. All of these are optional, but of course if you declare an Edge then the Nodes for that Edge are expected to be present!

Example: Nodes and Edges#

{  "nodes": [    { id:"1", name:"foo"  },    { id:"2", name:"baz"  },    { id:"3", name:"foo"  },    { id:"4", name:"ding" },    { id:"5", name:"dong" },    { id:"6", name:"ping" },    { id:"7", name:"pong" }  ],  "edges":[    { source:"1", target:"2" },    { source:"1", target:"3" },    { source:"2", target:"4" },    { source:"2", target:"5" },    { source:"3", target:"6" },    { source:"3", target:"7" }                  ]}

Example: Groups, Nodes and Edges#

{  "groups":[    { "id":"group1", name:"Group One" },    { "id":"group2", name:"Group Two" }  ],  "nodes": [    { id:"1", name:"foo", group:"group1"  },    { id:"2", name:"baz"  },    { id:"3", name:"foo"  },    { id:"4", name:"ding", group:"group2" },    { id:"5", name:"dong", group:"group2" },    { id:"6", name:"ping" },    { id:"7", name:"pong" }  ],  "edges":[    { source:"1", target:"2" },    { source:"1", target:"3" },    { source:"2", target:"4" },    { source:"2", target:"5" },    { source:"3", target:"6" },    { source:"3", target:"7" }                  ]}


Port data is embedded inside the data for the vertex to which it belongs, and decoded via a portExtractor or portDataProperty. See this page for details of these approaches.

Loading Graph JSON#

toolkitInstance.load({  type:"json",  url:""});

Since Graph JSON is the default syntax, you can in fact omit the type parameter in the above example:

toolkitInstance.load({  url:""});

Hierarchical JSON Syntax#

This JSON syntax represents hierarchical data, in which every Node may have zero or more child Nodes. It is assumed that there is an Edge between a Node and each of its child Nodes. Note that the children member on each Node's data is optional.

{  "id":"foo",  "name":"FOO!",  "children":[    {      "id":"bar",      "name":"BAR!",      "children":[        {          "id":"baz",          "name":"BAZ!"        }      ]    },    {      "id":"qux",      "name":"QUX!"    }  ]}

Loading Hierarchical JSON#

toolkitInstance.load({  type:"hierarchical-json",  url:""});


You can either tell the Toolkit to save data on demand, using the save function, or configure it to save automatically, whenever it detects that the data model has changed.

The Toolkit uses an HTTP POST to save data. You cannot configure it to use anything other than a POST. If you absolutely do not want to use POST, then you can use the method described at the bottom of this page to export the data, then save it yourself.

Save on demand#{  type:"json",  url:"",  parameters:{ "foo":1, "bar":2 },  success:function() {  },  error:function() {  },  headers:{ "Optional":"Http Headers"}})

Here, as with the load function, the type of the dataset is assumed to be the Toolkit's default JSON syntax (see below for an example of how to write a custom exporter).

The allowed parameters are:

  • type By default this is set to "json". Specifies the data type in which to format the data. This must match the name of an exporter registered with the given instance of the Toolkit.
  • url Required. URL to POST data to.
  • parameters Optional parameters to pass to the exporter. If you write a custom exporter you may wish to use this.
  • success Optional callback to execute once the data has saved successfully.
  • error Optional callback to execute if there was an error saving the data.
  • headers Optional headers to set on the ajax request. By default, the Toolkit will send a Content-Type:"application/json" header. If you provide your own headers this header will continue to be sent, unless of course you override it.

Save Automatically#

You can configure the Toolkit to save automatically, either with its own ajax call, or by invoking a function you supply. The bare minimum setup requires the autoSave flag to be set, and then either a saveUrl:

var t = jsPlumbToolkitBrowserUIVanilla.newInstance({  autoSave:true,  saveUrl:""});

...or an autoSaveHandler function for the Toolkit to invoke:

var t = jsPlumbToolkitBrowserUIVanilla.newInstance({  autoSave:true,  autoSaveHandler:(toolkitInstance) => {        }});

The Toolkit will save the dataset whenever one of these methods is called:

  • addNode
  • removeNode
  • addNodes
  • addEdge
  • removeEdge
  • addPort
  • addNewPort
  • removePort
  • updateNode
  • updateEdge
  • updatePort
  • addToGroup
  • removeFromGroup

Note the dataset will not be saved automatically when you call the clear method.

If you find that having this switched on is causing too much network traffic due to rapid changes in the dataset, you can instruct the Toolkit to "debounce" these requests - limit the rate at which save requests will be made, via the autoSaveDebounceTimeout constructor parameter:

var t = jsPlumbToolkitBrowserUIVanilla.newInstance({  autoSave:true,  saveUrl:"",  autoSaveDebounceTimeout:1000});

This is a value in milliseconds.

Autosave Callbacks#

You can supply callbacks for auto save success and error, as well as functions to run before and after an auto save operation. These functions are not invoked if you supply an autoSaveHandler, since the Toolkit in that case does not perform the save operation itself.

var t = jsPlumbToolkitBrowserUIVanilla.newInstance({  autoSave:true,  saveUrl:"",  onAutoSaveError:function(msg) { ... },  onAutoSaveSuccess:function(response) { ... },  onBeforeAutoSave:function() { ... },  onAfterAutoSave:function() { ... }});

Autosave HTTP Headers#

To set headers as discussed below when auto-saving, provide a saveHeaders object in the Toolkit's constructor.

These are only used when you supply a saveUrl. If you supply an autoSaveHandler these are, of course, ignored.

var toolkit = jsPlumbToolkitBrowserUIVanilla.newInstance({  autoSave:true,  saveUrl:"",  saveHeaders:{    "X-My-Header":"My Header Value"  }});

Content Type#

The Toolkit will, by default, set the Content-Type header on a save POST to:


Specifying HTTP Headers#

You can set arbitrary headers (including to override Content-Type) via the headers parameter on a save call:{  url:"",  headers:{    "X-My-Header":"headerValue"  }});



If you want to just export the data, you can do the following:

var data = toolkitInstance.exportData();

This will assume you want the data in the Toolkit's default JSON syntax. If you have a custom exporter you wish to use, you can specify that using the type parameter. You can also pass in parameters for the export:

var data = toolkitInstance.exportData({  type:"myFormat",  parameters:{    importantNumber:34,    somePrefix:"foo-"  }});