Skip to main content

Angular

If you want to integrate JointJS+ with Angular, you're in the right place! This tutorial will help you create a project, and after a few minutes, have a working JointJS+ Angular application.

The source code for this tutorial can be found on GitHub. Looking for a different version of your favourite framework? Be sure to checkout the different branches of the repository to see if you find what you need.

info

This tutorial adds JointJS+ via a joint-plus.tgz installable archive. Sign up to receive yours! If using the open-source JointJS library, you can still adapt the following integration steps to Angular and the @joint/core package. Just follow the JointJS code in our Quickstart guide instead.

Create an Angular projectโ€‹

In order to create our Angular project, we will follow the recommended setup in the Angular documentation.

npx -p @angular/cli ng new joint-plus-tutorial-angular

We will be prompted to choose some options about project configuration. Select the following:

  • Which stylesheet format would you like to use? โ€บ CSS
  • Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? โ€บ No

After the setup is complete, we can change to the correct directory.

cd joint-plus-tutorial-angular

Add JointJS+ to the Angular projectโ€‹

We can add JointJS+ to the project by placing the installable archive joint-plus.tgz in the root directory of the Angular application, and installing @joint/plus via our preferred package manager. All project dependencies will be installed alongside @joint/plus too.

npm add joint-plus.tgz

In tsconfig.json, we will also set strictPropertyInitialization to false.

"compilerOptions": {
"strictPropertyInitialization": false
},

Build the Angular applicationโ€‹

Before we get started, let's clean up the existing project a little bit.

  • Open src/app/app.component.html, and remove everything
  • Open src/app/app.component.ts, and remove the following line title = 'joint-plus-tutorial-angular';

The current state of app.component.ts should be as follows:

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent {}

Let's add some global styles by placing the following CSS rules in src/styles.css.

@import "@joint/plus/joint-plus.css";

body {
height: 100vh;
box-sizing: border-box;
margin: 0;
}

.canvas {
width: 100%;
height: 100%;
}

.joint-paper {
border: 1px solid #A0A0A0;
}

Now that the basic setup is completed, we are ready to create our JointJS+ Angular application. We will take advantage of a number of Angular features in app.component.ts. ngOnInit() and ngAfterViewInit() are Angular lifecycle hooks that enable running code at a certain times in the lifecycle of a component. ViewChild is a decorator that allows us access to native DOM elements that have a template reference variable.

The relevant JointJS+ code is also imported, and a few class properties are declared.

import { AfterViewInit, OnInit, Component, ElementRef, ViewChild  } from '@angular/core';
import { dia, ui, shapes } from '@joint/plus';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent implements OnInit, AfterViewInit {
@ViewChild('canvas') canvas: ElementRef;

private graph: dia.Graph;
private paper: dia.Paper;
private scroller: ui.PaperScroller;

public ngOnInit(): void {}

public ngAfterViewInit(): void {}
}

In app.component.html, we can add a #canvas template variable to our div element.

<div class="canvas" #canvas></div>

Inside the ngOnInit method, we can add the Graph, Paper, and PaperScroller.

const graph = this.graph = new dia.Graph({}, { cellNamespace: shapes });

const paper = this.paper = new dia.Paper({
model: graph,
background: {
color: '#F8F9FA',
},
frozen: true,
async: true,
cellViewNamespace: shapes
});

const scroller = this.scroller = new ui.PaperScroller({
paper,
autoResizePaper: true,
cursor: 'grab'
});

Next, let's render our PaperScroller component, create a simple Rectangle shape, and add it to our Graph. Once again, in ngOnInit.

scroller.render();

const rect = new shapes.standard.Rectangle({
position: { x: 100, y: 100 },
size: { width: 100, height: 50 },
attrs: {
label: {
text: 'Hello World'
}
}
});

graph.addCell(rect);

Inside the ngAfterViewInit method, let's append the PaperScroller to our ref that we created earlier. Afterwards, we can position the Paper in the center of the PaperScroller viewport, and unfreeze the Paper.

const { scroller, paper, canvas } = this;
canvas.nativeElement.appendChild(this.scroller.el);
scroller.center();
paper.unfreeze();

That's all it takes to create a simple JointJS+ Angular application. The final application code is as follows:

import { AfterViewInit, OnInit, Component, ElementRef, ViewChild  } from '@angular/core';
import { dia, ui, shapes } from '@joint/plus';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css'
})
export class AppComponent implements OnInit, AfterViewInit {
@ViewChild('canvas') canvas: ElementRef;

private graph: dia.Graph;
private paper: dia.Paper;
private scroller: ui.PaperScroller;

public ngOnInit(): void {
const graph = this.graph = new dia.Graph({}, { cellNamespace: shapes });

const paper = this.paper = new dia.Paper({
model: graph,
background: {
color: '#F8F9FA',
},
frozen: true,
async: true,
cellViewNamespace: shapes
});

const scroller = this.scroller = new ui.PaperScroller({
paper,
autoResizePaper: true,
cursor: 'grab'
});

scroller.render();

const rect = new shapes.standard.Rectangle({
position: { x: 100, y: 100 },
size: { width: 100, height: 50 },
attrs: {
label: {
text: 'Hello World'
}
}
});

this.graph.addCell(rect);
}

public ngAfterViewInit(): void {
const { scroller, paper, canvas } = this;
canvas.nativeElement.appendChild(this.scroller.el);
scroller.center();
paper.unfreeze();
}
}

To serve our JointJS+ Angular application, we can use ng serve. Lastly, let's visit the url suggested by our terminal in the browser, and we should see our JointJS+ Angular application!

See it in actionโ€‹

Here is the example of an Angular application with integrated JointJS+:

Frequently asked questionsโ€‹

Do you support Angular version X?โ€‹

You can integrate JointJS with any version of Angular - see below.

Learn more...

Angular changes between versions usually don't affect JointJS library code. You should try running one of our Angular example applications (apps/Chatbot/Angular16 or apps/KitchenSink/Angular16) in your environment and see if it works. We can advise if it doesn't.

Use the Angular tutorial to get started - see above.

info

JointJS example applications (including the Angular tutorial) make use of Webpack v5, which is only officially supported by Angular v12+. This causes issues when these example applications are run without modification in an older version of Angular.

Ideally, you would update your Angular project to a version which uses Webpack v5.

What if I cannot update my Angular project to a version which supports Webpack v5?

You can try some of the fixes below:

Update Webpack config to support .mjs files:

In your project, it's likely that Webpack cannot locate/recognize .mjs files. To address this issue you have to update the Webpack config.

If you have access to the webpack.config.js file, you can add the following:

resolve: {
extensions: ['*', '.mjs', '.js', '.json']
},
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto',
}
]
}
What if I don't have access to webpack.config.js?

If you have created your Angular project with the Angular CLI, it's likely that you don't have access to the Webpack config file as it is hidden from the user.

If ng eject (the command to expose the webpack.config.js file) is not available in your version of Angular, there is a package which allows you to create a custom webpack config without ejecting the Angular CLI project: https://www.npmjs.com/package/@angular-builders/custom-webpack

It can be added to your project via npm install @angular-builders/custom-webpack@8.4.1 -D

This will allow you to create a webpack configuration in the angular.json file. You have to update the build and serve sections as follows:

"architect": {
...
"build": {
"builder": "@angular-builders/custom-webpack:browser"
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js",
"mergeStrategies": {
"externals": "replace"
}
...
}
},
...
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
},
}
}

You can find more information at the following link: https://github.com/just-jeb/angular-builders/blob/8.x.x/packages/custom-webpack/README.md

Now, you can create the webpack config file extra-webpack.config.js in the root of your project. It can contain the following:

module.exports = {
mode: 'production', // "production" | "development" | "none"
resolve: {
extensions: ['*', '.mjs', '.js', '.json']
},
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto'
}
]
}
};

At this point, if you run npm run start, the original errors from Webpack will be fixed, but some new errors related to JavaScript features will appear.

Add support for newer JavaScript features:

Webpack v4 doesn't support newer JavaScript features used by JointJS in its source code (for example es2020). You can add Babel packages to your project to support them:

npm install babel-loader@8.2.5 -D
npm install @babel/plugin-proposal-nullish-coalescing-operator -D
webpack.config.js

And update the webpack.config.js accordingly:

module.exports = {
mode: 'production', // "production" | "development" | "none"
resolve: {
extensions: ['*', '.mjs', '.js', '.json']
},
module: {
rules: [
{
test: /\.mjs$/,
include: /node_modules/,
type: 'javascript/auto',
use: {
loader: 'babel-loader',
options: {
presets: [
['@babel/preset-env', { targets: "defaults" }]
],
plugins: ['@babel/ plugin-proposal-nullish-coalescing-operator']
}
}
}
]
}
};

Running npm run start will be successful now.

As mentioned above, ideally you would just update to a supported version of Angular that uses Webpack v5, if possible, as it would solve all of these issues.

How can I integrate JointJS with Angular?โ€‹

Use the Angular tutorial to get started - see above.

Learn more...

The key to understand with the Angular tutorial is that it serves as a template to which the code from other JointJS examples can be added - see below.

tip

Your JointJS+ package contains two boilerplate JointJS + Angular applications out-of-the-box:

  • Chatbot (online demo) - source code can be found in the unzipped JointJS+ package in the folder apps/Chatbot/Angular16.

  • KitchenSink (online demo) - source code can be found in the unzipped JointJS+ package in the folder apps/KitchenSink/Angular16.

You should inspect their source code to identify some of the best practices for writing a full-featured JointJS+ app inside an Angular environment.

We also provide additional example content written specifically in Angular - see below.

Do you have demo X available in Angular?โ€‹

We have a few demos written specifically in Angular, but not all of them. However, the modular nature of JointJS makes it possible to adapt any JointJS example to Angular - see below.

Learn more...

Angular examples in your trial package:

In the JointJS+ trial package, you can find Angular versions of our Chatbot and KitchenSink applications:

  • Chatbot (online demo) - source code can be found in the unzipped JointJS+ package in the folder apps/Chatbot/Angular16.

  • KitchenSink (online demo) - source code can be found in the unzipped JointJS+ package in the folder apps/KitchenSink/Angular16.

Angular examples in our Angular tutorial GitHub repository:

We also provide our Diagram Index and Tabs demos in Angular. The source code can be found on GitHub at the links below:

tip

Make sure to check out the other branches of the repository for additional Angular content.

Other Angular content:

We also have an Angular tutorial, which covers the basics of the integration - see above.

How can I add the code from a JointJS example to my Angular application?โ€‹

Most of our demos / applications / CodePens aren't written specifically in Angular, but the modular nature of JointJS makes it possible to adapt any JointJS example to Angular.

Learn more...

Use the Angular tutorial to get started - see above.

The key to understand with the Angular tutorial is that it serves as a template to which the code from other examples can be added. If you get the demo from the tutorial working, then you are 90% of the way there to get any other JointJS example working in Angular.

Basically, the application created in the Angular tutorial acts as a shell, into which you can copy-paste any JointJS code. You just need to use the paper and graph variables from the tutorial's ngOnInit() function to orient yourself - all JointJS examples have these variables as well. Simply copy-paste paper + graph + all other JointJS code from the example into the ngOnInit() function in the tutorial application you got working, and almost all functionality will start working out-of-the-box (for the rest - e.g. asynchronous rendering - refer to the notes inside the Angular tutorial).