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.
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
- pnpm
- yarn
npm add joint-plus.tgz
pnpm add ./joint-plus.tgz
yarn add @joint/plus@file: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 linetitle = '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.
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:
- webpack.config.js
- extra-webpack.config.js
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']
}
}
}
]
}
};
npm install babel-loader@8.2.5 -D
npm install @babel/plugin-proposal-nullish-coalescing-operator -D
extra-webpack.config.js
And update the extra-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.
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:
-
Diagram Index (online demo) - source code can be found in a branch of our Angular tutorial GitHub repository.
-
Tabs (online demo) - source code can be found in a branch of our Angular tutorial GitHub repository.
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).