Skip to main content

Loading and saving data

Getting data into and out of the Toolkit is easy.

Node, Group, Edge and Port Data

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

Nodes

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(node.data.aValue);
--> 567

Groups

Groups behave in the same way as nodes. Imagine you had this group data:

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

This JSON object is available on the resulting Groups instance as the data variable, and, as with nodes, this object is also what is passed to the templating code.

Ports

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

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 Connections. Here is the equivalent code to the snippet given for Nodes above:

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

Loading

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

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. If you have not cleared the data when you reload some dataset, the Toolkit will not load new items if an item of the given type with that id already exists, which is generally the case for nodes/groups, but often edges are not loaded with their own ids, and therefore on reload will be duplicated.

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:() => {
// 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:"Hierarchy"
}
});

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" }
]
}

Ports

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:"http://mydata.com?xyz"
});

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

toolkitInstance.load({
url:"http://mydata.com?xyz"
});

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:"http://myhierarchicaldata.com?xyz"
});

Saving

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

toolkitInstance.save({
type:"json",
url:"http://foo.com",
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:"http://foo.com"
});

...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:"http://foo.com",
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:"http://foo.com",
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:"http://sava-data.com",
saveHeaders:{
"X-My-Header":"My Header Value"
}
});

Content Type

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

Content-Type:"application/json"

Specifying HTTP Headers

You can set arbitrary headers (including to override Content-Type) via the headers parameter on a save call:

toolkit.save({
url:"http://save-data.com",
headers:{
"X-My-Header":"headerValue"
}
});

TOP


Exporting

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-"
}
});