Integrations / Angular 1.x Integration

Angular 1.x Integration

The jsPlumb Toolkit offers several components to assist you in integrating with Angular 1.x. The Toolkit uses "strict" format in all of its Angular components. For Angular 10/9/8/7/6/5/4/2 integration, refer to this page.


The Toolkit's Angular 1.x components are stored in a separate file - jsplumbtoolkit-angular-1.x.js. You need to import this file, after you import the Toolkit.

The Angular components are stored inside a module called $jsPlumb:

var app = angular.module('app', ['$jsPlumb']);

This directive creates a Toolkit instance and renders it to the given element.

<jsplumb-toolkit surface-id="mySurface" jtk-id="myToolkit" params="ToolkitParams" renderParams="RenderParams">

    You can put content in here.

</jsplumb-toolkit>
Attributes
  • jtk-id Identifier for the Toolkit. Strictly speaking this is not required, but if you need to access the Toolkit via the jsPlumbService you will need to have set this.

  • [surface-id] Provides the identifier to associate with the created Surface widget. This is optional, but you will need to provide this if you wish to attach a jsplumb-miniview or jsplumb-palette.

  • [params] Optional reference to parameters for the Toolkit constructor. By "reference" we mean the name of some variable that is in the scope in which the directive is executing.

  • [renderParams] Optional reference to parameters for the render call. By "reference" we mean the name of some variable that is in the scope in which the directive is executing.

  • [init] Optional reference to a function that will be called once the Toolkit and Surface have both been instantiated. The function's method signature is:

init(scope, element, attrs, controller);
  • [data] Optional reference to some Object in scope that contains the data for the Toolkit to load.

jsplumb-miniview

Creates a Miniview:

<jsplumb-miniview surface-id="mySurface"></jsplumb-miniview>
Attributes
  • surface-id The ID of the Surface widget to which this Miniview should attach itself. Required.

Note When using the jsplumb-toolkit Angular directive you must use the jsplumb-miniview directive to configure a Miniview. Any miniview declared in the renderParams will be ignored.

jsplumb-palette

This directive is declared as both an Attribute and Element directive. Here it is used as an Attribute directive:

<div class="someClass" jsplumb-palette selector="li" generator="SomeController.dataGenerator">
    <ul>
        <li data-type="foo">FOO</li>
        <li data-type="bar">BAR</li>
    </ul>
</div>
Attributes
  • jsplumb-palette This is what turns the directive on for the element.
  • selector A CSS3 selector identifying which child elements should be draggable/droppable.
  • generator The name of a function that is in scope that will be used to generate a dataset for a node that is being dragged.

In the example markup above, a suitable generator function (here declared on SomeController) might be:

this.dataGenerator = function(element) {
    return { type: element.getAttribute("data-type") };    
};

When using the Angular integration you do not need to use Angular to render your nodes if you do not want to - you can use the standard Toolkit templating mechanism. If you wish to use Angular, though, you will need to create a directive for each Node type, and you'll need to use the jsPlumbFactory to do this. Here's an example from the angular integration demo (which is the Flowchart Builder application converted to use Angular):

var app = angular.module('app', ['$jsPlumb']);
...
...
app.directive('question', function (jsPlumbFactory) {
    return jsPlumbFactory.node({
        inherit:["removeNode", "editNode"],
        templateUrl: "question_template.tpl",
        link:function(scope, element) {
            element.addClass("flowchart-object flowchart-question");
        }
    });
}); 

The key here is the call to jsPlumbFactory.node. This method takes care of setting everything you need; you provide the URL of the template to use and optionally a link function. You'll also notice a parameter called inherit in this example - this is discussed below.

templateUrl

You cannot provide an inline template; your templates must be declared somewhere in your HTML.

A link function is not required, but can be provided if you wish. In the Toolkit's Angular demo, the link function is used to get around the fact that when the Toolkit renders Nodes via Angular, there is no declarative way of setting attributes (such as the class name) on that directive's root element. So in this link function you can see we retroactively set a couple of classes on the Node's root element.

inherit

This concept is not a core Angular concept. It is a helper that enables you to declare items from your Controller's scope that you wish to have in your Node's scope. The mechanism used by the Toolkit, out of necessity, creates an isolated scope for each Node. The inherit mechanism will pull named items out of the isolated scope's ancestors and copy them in to the isolate scope itself. In the Toolkit's Angular example, removeNode and editNode are functions declared in the controller's scope that all Nodes need to have access to.


Accessing Toolkit/Surface instances

To access instances of the Toolkit or of the Surface widget, you can use the jsPlumbService:

app.controller("FooController", [ "jsPlumbService", function(jsPlumbService) {
    var toolkit = jsPlumbService.getToolkit("myToolkit");
    var surface = jsPlumbService.getSurface("mySurface");
}]);

Resetting a Toolkit instance

Should you wish to clear a Toolkit instance (this is not the same as the Toolkit's own clear method: this is for clearing a Toolkit reference out from the service, so that subsequent requests for the Toolkit with the given ID will cause a new Toolkit to be created), you can make this call:

jsPlumbService.resetToolkit("myToolkit");

Binding Events

To bind to an event on a Toolkit, which may or may not yet exist, you can use the service's bind method:

app.controller("FooController", [ "jsPlumbService", function(jsPlumbService) {
    jsPlumbService.bind("ready", "myToolkit", function() {
        alert("The toolkit is ready");
    });    
}]);

In most cases when you try to bind to a Toolkit it will have been created. In the above example it may well not have been; in general you can use this method for safety if you haven't yet got a concrete handle on the Toolkit instance you want.


If you're using Ports in your application there's a limitation with the template engine you need to be aware of. When a Node is rendered, using a directive, Angular has not yet bound the data to the DOM. This means that if you had a template like this, say:

<div data-id="{{node.id}}">
 Hello
</div>

The data-id attribute would not have a value immediately after rendering. In most cases this is not a problem, but say you have this:

<div>
   <h1>Hello</h1>
   <jtk-port ng-repeat="port in node.ports" port-id="{{port.id}}" port-type="default"/>
</div>

This is more of a problem, since the value of the port-id attribute is used by jsPlumb to wire up the UI to the data model. In this case, that value will be "{{port.id}}", for every Port. There does not seem to be a way around this using templating alone. In this case, you need to add the Ports after the fact, in the nodeAdded event of your render parameters:

var surface = someToolkit.render({
    container:someElement,
    nodes:{ ... },
    ports:{
        "default":{
            isEndpoint:true
        }
    },
    events:{
        nodeAdded:function(p) {    
            for (var i = 0; i < p.node.data.ports; i++) {
                someToolkit.addNewPort(p.node, "default", p.node.data.ports[i]);
            }
        }
    }
});