DEMOS
DOCS
FEATURES
DOWNLOAD
PURCHASE
CONTACT
BLOG

Templating

Introduction

One great feature of the jsPlumb Toolkit is the way client side templating is baked right in - your Node, Group and Port definitions in the View declare the id of some template to use and the Toolkit takes care of the rest.

Rotors is the default template adapter in the jsPlumb Toolkit. You can use any templating mechanism you want to - you just need to write an appropriate adapter, and provide this function as the value of the templateRenderer parameter - but it is recommended that you use Rotors, because Rotors' ability to update previously rendered content means that you can update your UI "automatically" from a change to the data.

Here's what the table template looks like in the Database Visualizer application:

<script type="jtk" id="tmplTable">
  <div class="table">
    <div class="table-name">
      ${name}
      <div class="new-column" title="Click to add a new column">+</div>
    </div>
    <ul class="table-columns">
      <r-each in="columns">
        <r-tmpl id="tmplColumn"></r-tmpl>
      </r-each>             
    </ul>
  </div>
</script>

and here's tmplColumn:

<script type="jtk" id="tmplColumn">
  <li class="table-column table-column-type-${type} table-column-primary-key">
    <div class="table-column-delete" data-port-id="${id}">x</div>
    ${id}
    <jtk-source port-id="${id}" port-type="column" scope="${datatype}"></jtk-source>
    <jtk-target port-id="${id}" port-type="column" scope="${datatype}"></jtk-target>
  </li>
</script>

Notice any non-standard HTML in there? The jsPlumb Toolkit supports declarative source/target/endpoint configuration, discussed in Connectivity below.

These templates are matched to Node/Port types in the Database Visualizer's view. Here's an edited snippet of the view:

nodes: {
  "table": {
    template: "tmplTable"
  }
  ...
},
...
ports: {
  "default": {
    template: "tmplColumn",
    ...
  }
}

Limitations

When using the default template engine, your templates must return a single root node. If you return multiple nodes, the Toolkit will use the first node only.


Inferring Template IDs

As shown above, the Node and Port definitions passed as part of the view parameter on a render call allow you to specify a template to be used to render an instance of the given type. Sometimes you will find that you have nothing other than a template directive in a Node or Port definition. So to cut down on boilerplate, the Toolkit will make a guess at a suitable template id if you do not provide.

The inferred template id consists of "jtk-template-" as a prefix, followed by the type of the object. So in the previous example, a Node of type table would have an inferred template id of jtk-template-table.


Custom Template Resolver

The default template resolution mechanism is to look for a <script> element in the DOM with an ID matching the ID of the template to retrieve. You can supply your own template resolver like this:

toolkit.render({
  container:...,
  view:{ ... },
  templateResolver:function(templateId) {
    // find the matching template and return it - as a String.
  }
});

Providing Templates Directly

Another option is to pass a map of templates into the render call:

toolkit.render({
  container:...,
  view:{ ... },
  templates:{
    type1:"<div><span>type 1</span>...</div>",
    type2:"<div><span>type 2</span>...</div>",
  }
});

For some use cases, where the templates are not overly complex, this can be handy.


Configuring Connectivity

Note from version 1.2.6 onwards this information applies to Groups as well as Nodes/Ports. Prior to version 1.2.6 this applies only to Nodes and Ports.

jtk- Elements

To configure your UI to allow for the user to establish connections using the mouse, you use one or more custom tags in your HTML templates. In the previous section, we saw a template that had a jtk-source and a jtk-target element; these were used to declare that the given element should act as both a connection source and connection target.

A third custom element available in the jsPlumb Toolkit is jtk-port - used to declare an Endpoint on some element.

A full discussion of each element follows.

jtk-source

This element is used when you want to configure some element as a connection source. It is analogous (and maps directly to) the makeSource method in jsPlumb. The element that is configured as the connection source is that element which is the parent of the jtk-source element - here, it's the .table-column li.

Five attributes are supported on the jtk-source element (two of which are not shown in this example):

  • port-id

This defines the id of the port on the node. It is not mandatory: if you use the jtk-source element to turn some Node into a connection source, then you don't need to set this attribute - you are configuring the Node's default Port. If you wish to assign this connection source to a Port, though, then you must set this attribute. This attribute's value must be unique on its Node, but may be the same as the id of some Port on another Node. Here we are using the id member of the data backing the column.

  • port-type

Maps to a Port type in the view, as discussed above. Note that you can set this even if you don't set port-id, as you will want to associate a Node's default Port with some type.

  • scope

The jsPlumb Toolkit makes use of jsPlumb's scope concept to control, albeit in a relatively crude way, what can be connected to what. In this template you see that both the jtk-source and jtk-target elements use the same value for scope, and in the Database Visualizer this is mapped to the column's underlying datatype. There is a more sophisticated mechanism available to control connections should you need it, see Interceptors.

  • filter

Oftentimes you will want to configure an element as a connection source but not actually have the entire element respond to a connection drag start. This is quite common in the sorts of UIs for which the jsPlumb Toolkit is used: you need to be able to drag your nodes around the screen, but you'd also like to be able to drag connections from the nodes too. Using filter you provide a CSS selector that identifies elements from which connection drag should be supported.

  • filter-exclude

If you run into a problem specifying a suitable selector for the filter (:not selectors, in particular, are a little restricting), you can set filter-exclude:true, which will mean that the elements identified by the filter selector will be excluded from starting a drag.

jtk-target

This element is the opposite of the jtk-source element: it allows you to identify its parent as an element that you wish to configure as a connection target. It also has an analogue in jsPlumb to which it is directly mapped: makeTarget.

This element supports three of the five attributes supported by jtk-source. Their meaning and usage is the same:

  • port-id
  • port-type
  • scope

The fourth and fifth parameters - filter and filter-negate - are not supported, which means that it is always the entire element that is configured as a connection target. It is possible that, in the future, jsPlumb will support the filter and filter-negate attributes on the makeTarget method. If/when that happens, the Toolkit's jtk-target element will be updated to also support them.

jtk-port

Use this element when you want to have an Endpoint added to your UI. Its analogue in jsPlumb is the addEndpoint method. This element supports the same attributes as makeTarget, plus some extras:

  • port-id
  • port-type
  • scope

  • anchor-x This attribute can be used to specify the location, in the x axis, of the Anchor used by the Endpoint associated with this Port. This is a proportional value, as discussed in the anchor documentation.

  • anchor-y This attribute can be used to specify the location, in the y axis, of the Anchor.

  • orientation-x Used to associate an orientation, in the x axis, with the Anchor associated with the Port. Orientation is discussed in the anchor documentation linked above. This is optional, but if omitted, the default of 0 will be used.

  • orientation-y Used to associate an orientation, in the y axis, with the Anchor associated with the Port.

Note using this declarative means of configuring ports does not mean that the UI artefacts associated with the Endpoints exist in the DOM as children of the port's parent element. Remember that the Toolkit always makes use of jsPlumb's Container concept, to ensure that all of the Endpoints and Connections contained inside a given Surface have the same parent.

Note also that any jsPlumb Toolkit elements that are found during rendering are removed from the DOM after processing.


External Templates

To help you organize your templates better, you can store them in external files and reference them via a script import in your HTML:

<script type="text/x-jtk-templates" src="../palettes/shapes-svg.html"></script>

The key here is that the type is text/x-jtk-templates. There may be one or more templates declared in the specified file. This example is one from one of the Toolkit's unit tests; the file contains several templates. Here's the first two:

<script type="jtk" id="tmplRectangle">  
  <svg:svg style="position:absolute;left:0;top:0;">
    <svg:rect width="${width}" height="${height}" x="${strokeWidth}" y="${strokeWidth}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}" transform="rotate(${rotate} ${(width / 2) + strokeWidth} ${(height/2) + strokeWidth})"></svg:rect>
  </svg:svg>    
</script>

<script type="jtk" id="tmplCircle"> 
  <svg:svg style="position:absolute;left:0;top:0;">
    <svg:circle class="jtk-svg" cx="${cx}" cy="${cy}" r="${r}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}"></svg:circle>
    <jtk-port port-id="port" port-type="basic"></jtk-port>
  </svg:svg>    
</script>

You can have multiple x-jtk-templates scripts declared in your html. Note, though, that the loading of these scripts postpones the firing of the ready event in the Toolkit, so you should ensure you're not getting any 404s and what you are loading is loading quickly.