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 Schema Builder: 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.
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"
}
});
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-"
}
});