Context Menu in Angular Diagram Component
30 Aug 202524 minutes to read
In graphical user interfaces, a context menu appears when you perform a right-click operation, offering users a set of actions relevant to the current context. The Angular Diagram component provides extensive context menu customization capabilities through the contextMenuSettings
property.
The Diagram control includes built-in context menu items and allows you to define custom menu items. This flexibility enables you to tailor menus to specific application needs, including creating nested levels of menu items for complex user interactions.
Prerequisites
To ensure the context menu renders correctly, include the necessary CSS references from the Syncfusion® ej2-navigations
package by adding the following line to your src/styles.css
file:
@import "../node_modules/@syncfusion/ej2-navigations/styles/material.css";
Default Context Menu
The Diagram component provides default context menu items for frequently used commands. Use the show
property to enable or disable the context menu.
The following code demonstrates how to enable the default context menu items:
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramModule, DiagramContextMenuService, DiagramComponent, ShapeStyleModel } from '@syncfusion/ej2-angular-diagrams';
import { ContextMenuSettingsModel } from '@syncfusion/ej2-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [DiagramContextMenuService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px"[contextMenuSettings]="contextMenuSettings">
<e-nodes>
<e-node id='node1' [offsetX]=100 [offsetY]=100 [width]=100 [height]=100>
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle1">
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='node2' [offsetX]=300 [offsetY]=100 [width]=100 [height]=100>
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle2">
</e-node-annotation>
</e-node-annotations>
</e-node>
</e-nodes>
<e-connectors>
<e-connector id='connector1' type='Straight' sourceID='node1' targetID='node2'>
</e-connector>
</e-connectors>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public contextMenuSettings?: ContextMenuSettingsModel
ngOnInit(): void {
//Enables the context menu
this.contextMenuSettings = {
show: true,
}
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Customize Context Menu
You can customize context menus for individual nodes by defining specific menu items beyond the default options. To add custom context menu items, define and incorporate them into the items
property of the context menu.
Each custom item can be configured with the following properties:
-
text
: Display text for the menu item -
ID
: Unique identifier for the menu item -
iconCss
: CSS class for font icons -
target
: Specifies where the menu item should appear -
separator
: Adds visual separation between menu items
For nested menu structures, define child items within the items
property of a parent menu item.
Display Custom Menu Only
To display only custom context menu items, set the showCustomMenuOnly
property to true.
Context Menu Click
Handle custom menu item actions using the contextMenuClick
event. This event triggers when a menu item is clicked and allows you to define specific actions based on the selected item.
The following example demonstrates context menu click handling for node cloning and color changes:
import { DiagramModule, DiagramContextMenuService, DiagramComponent } from '@syncfusion/ej2-angular-diagrams'
import {Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { ContextMenuSettingsModel } from '@syncfusion/ej2-diagrams';
import { MenuEventArgs } from '@syncfusion/ej2-navigations';
@Component({
imports: [
DiagramModule
],
providers: [DiagramContextMenuService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [contextMenuSettings]="contextMenuSettings" (contextMenuClick)="contextMenuClick($event)">
<e-nodes>
<e-node id='node1' [offsetX]=100 [offsetY]=100 [width]=100 [height]=100 >
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle1" >
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='node2' [offsetX]=350 [offsetY]=150 [width]=100 [height]=100>
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle2">
</e-node-annotation>
</e-node-annotations>
</e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public contextMenuSettings?: ContextMenuSettingsModel;
ngOnInit(): void {
//Enables the context menu
this.contextMenuSettings = {
//Enables the context menu
show: true,
// Defines the custom context menu items
items: [{
// Text to be displayed
text: 'Fill',
items: [
{ id: 'red', text: 'Red' },
{ id: 'yellow', text: 'Yellow' },
{ id: 'green', text: 'Green' },
{ id: 'blue', text: 'Blue' },
],
//Sets the id for the item
id: 'fill',
target: '.e-elementcontent',
// Sets the css icons for the item
iconCss: 'e-icons e-paint-bucket',
},
{
text: 'Annotation color',
id: 'annotationColor',
items: [
{ id: 'pink', text: 'Pink' },
{ id: 'orange', text: 'Orange' },
{ id: 'violet', text: 'Violet' },
{ id: 'brown', text: 'Brown' },
],
target: '.e-elementcontent',
iconCss: 'e-icons e-font-color',
},
{
text: 'Clone',
id: 'clone',
target: '.e-elementcontent',
iconCss: 'e-icons e-copy',
},
],
// Hides the default context menu items
showCustomMenuOnly: true,
}
}
public contextMenuClick(args: MenuEventArgs): void {
let selectedNode = (this.diagram as any).selectedItems.nodes[0];
if (selectedNode && args.item.id !== 'fill' && args.item.id !== 'annotationColor') {
if (
args.item.text === 'Red' ||
args.item.text === 'Blue' ||
args.item.text === 'Yellow' ||
args.item.text === 'Green'
) {
selectedNode.style.fill = args.item.text;
(this.diagram as any).dataBind();
} else if (
args.item.text === 'Pink' ||
args.item.text === 'Violet' ||
args.item.text === 'Orange' ||
args.item.text === 'Brown'
) {
selectedNode.annotations[0].style.fill = args.item.text;
(this.diagram as any).dataBind();
} else {
(this.diagram as any).copy();
(this.diagram as any).paste();
}
}
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Context Menu Open
You can conditionally hide specific menu items based on selected elements using the contextMenuOpen
event. When the context menu opens via right-click, this event triggers and allows you to create an array of menu items to hide for the selected element. Pass this array to the hiddenItems
property of the contextMenuOpen event argument.
The following example shows how to display different custom menu items for nodes, connectors, and the diagram based on selection:
import {Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramModule, DiagramContextMenuService, DiagramComponent} from '@syncfusion/ej2-angular-diagrams'
import { MenuEventArgs } from '@syncfusion/ej2-navigations';
import { ContextMenuSettingsModel,DiagramBeforeMenuOpenEventArgs} from '@syncfusion/ej2-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [DiagramContextMenuService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [contextMenuSettings]="contextMenuSettings" (contextMenuOpen)="contextMenuOpen($event)" (contextMenuClick)="contextMenuClick($event)">
<e-nodes>
<e-node id='node1' [offsetX]=100 [offsetY]=100 [width]=100 [height]=100 >
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle1">
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='node2' [offsetX]=300 [offsetY]=100 [width]=100 [height]=100 >
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle2">
</e-node-annotation>
</e-node-annotations>
</e-node>
</e-nodes>
<e-connectors>
<e-connector id='connector1' type='Straight' sourceID='node1' targetID='node2'>
</e-connector>
</e-connectors>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public contextMenuSettings?: ContextMenuSettingsModel;
ngOnInit(): void {
//Enables the context menu
this.contextMenuSettings = {
show: true,
items: [
{
text: 'Change fill',
id: 'applyFill',
target: '.e-diagramcontent',
iconCss: 'e-icons e-paint-bucket',
},
{
text: 'Change stroke',
id: 'applyStroke',
target: '.e-diagramcontent',
iconCss: 'e-icons e-edit',
},
{
text: 'Select All',
id: 'selectAll',
target: '.e-diagramcontent',
},
],
// Hides the default context menu items
showCustomMenuOnly: true,
}
}
public contextMenuOpen(args: DiagramBeforeMenuOpenEventArgs): void {
let hiddenItems = [];
let selectedNode = (this.diagram as any).selectedItems.nodes[0];
let selectedConnector = (this.diagram as any).selectedItems.connectors[0];
if (selectedNode || selectedConnector) {
hiddenItems.push('selectAll');
} else {
hiddenItems = ['applyFill', 'applyStroke'];
}
args.hiddenItems = hiddenItems
}
public contextMenuClick(args: MenuEventArgs): void {
let selectedNode = (this.diagram as any).selectedItems.nodes[0];
let selectedConnector = (this.diagram as any).selectedItems.connectors[0];
if (selectedNode || selectedConnector) {
if (selectedNode) {
if (args.item.id === 'applyFill') {
selectedNode.style.fill =
selectedNode.style.fill === '#6BA5D7' ? 'green' : '#6BA5D7';
} else if (args.item.id === 'applyStroke') {
selectedNode.style.strokeColor =
selectedNode.style.strokeColor === 'black' ? 'yellow' : 'black';
}
}
if (selectedConnector) {
if (args.item.id === 'applyFill') {
selectedConnector.targetDecorator.style.fill =
selectedConnector.targetDecorator.style.fill === 'yellow'? 'black': 'yellow';
}
selectedConnector.style.strokeColor =
selectedConnector.style.strokeColor === 'black' ? 'yellow': 'black';
}
} else {
(this.diagram as any).selectAll();
}
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Context Menu with URL
Use the url
property of menu items to set website URLs that open when clicked.
The following example demonstrates context menu items with URLs for three websites:
import {Component, ViewEncapsulation, OnInit, ViewChild} from '@angular/core'
import { DiagramModule, DiagramContextMenuService,DiagramComponent } from '@syncfusion/ej2-angular-diagrams'
import { ContextMenuSettingsModel } from '@syncfusion/ej2-diagrams';
@Component({
imports: [
DiagramModule
],
providers: [DiagramContextMenuService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [contextMenuSettings]="contextMenuSettings">
<e-nodes>
<e-node id='node1' [offsetX]=100 [offsetY]=100 [width]=100 [height]=100>
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle1">
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='node2' [offsetX]=300 [offsetY]=100 [width]=100 [height]=100>
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle2" >
</e-node-annotation>
</e-node-annotations>
</e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public contextMenuSettings?: ContextMenuSettingsModel;
ngOnInit(): void {
//Enables the context menu
this.contextMenuSettings = {
//Enables the context menu
show: true,
items: [
{
text: 'Google.com',
id: 'google',
target: '.e-diagramcontent',
url: 'https://www.google.co.in/',
},
{
text: 'w3schools.com',
id: 'W3Schools',
target: '.e-diagramcontent',
url: 'https://www.w3schools.com/',
},
{
text: 'stackoverflow.com',
id: 'stackoverflow',
target: '.e-diagramcontent',
url: 'https://stackoverflow.com/',
}],
// Hides the default context menu items
showCustomMenuOnly: true,
}
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Template Support for Context Menu
The Diagram component provides template support for context menu customization. Customize menu item templates before rendering using the contextMenuBeforeItemRender
event, which triggers while rendering each menu item.
The following example renders menu items with shortcut key codes for specific actions. Key codes for cut, copy, and paste actions display in the right corner of menu items by adding a span element in the contextMenuBeforeItemRender
event:
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { createElement } from "@syncfusion/ej2-base";
import { DiagramModule, DiagramContextMenuService ,DiagramComponent } from '@syncfusion/ej2-angular-diagrams';
import { ContextMenuSettingsModel } from '@syncfusion/ej2-diagrams';
import { MenuEventArgs } from '@syncfusion/ej2-navigations';
@Component({
imports: [
DiagramModule
],
providers: [DiagramContextMenuService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [contextMenuSettings]="contextMenuSettings" (contextMenuBeforeItemRender)='contextMenuBeforeItemRender($event)'>
<e-nodes>
<e-node id='node1' [offsetX]=100 [offsetY]=100 [width]=100 [height]=100>
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle1">
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='node2' [offsetX]=300 [offsetY]=100 [width]=100 [height]=100 >
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle2">
</e-node-annotation>
</e-node-annotations>
</e-node>
</e-nodes>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public contextMenuSettings?: ContextMenuSettingsModel;
ngOnInit(): void {
//Enables the context menu
this.contextMenuSettings = {
//Enables the context menu
show: true,
items: [{
text: 'Cut ', id: 'cut', target: '.e-diagramcontent',
iconCss: 'e-cut e-icons'
},
{
text: 'Copy ', id: 'copy', target: '.e-diagramcontent',
iconCss: 'e-icons e-copy'
},
{
text: 'Paste', id:'paste', target: '.e-diagramcontent',
iconCss: 'e-icons e-paste'
}],
//hides the default context menu items
showCustomMenuOnly: true,
}
}
public contextMenuBeforeItemRender(args: MenuEventArgs) {
// To render template in li.
let shortCutSpan: HTMLElement = createElement('span');
let text: string = args.item.text as string;
let shortCutText: string = text === 'Cut ' ? 'Ctrl + X' : (text === 'Copy ' ?
'Ctrl + C' : 'Ctrl + V');
shortCutSpan.textContent = shortCutText;
args.element.appendChild(shortCutSpan);
shortCutSpan.setAttribute('class', 'shortcut');
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));
Context Menu Events
The following events are available for context menu interactions:
Event | Description |
---|---|
contextMenuBeforeItemRender |
Triggers while initializing each menu item. |
contextMenuOpen |
Triggers upon right-click before opening the context menu. |
contextMenuClick |
Triggers when a menu item is clicked. |
The following example demonstrates how to handle these events:
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
import { DiagramModule, DiagramContextMenuService,DiagramComponent } from '@syncfusion/ej2-angular-diagrams';
import { ContextMenuSettingsModel,DiagramBeforeMenuOpenEventArgs, } from '@syncfusion/ej2-diagrams';
import { MenuEventArgs } from '@syncfusion/ej2-navigations';
@Component({
imports: [
DiagramModule
],
providers: [DiagramContextMenuService],
standalone: true,
selector: "app-container",
template: `<ejs-diagram #diagram id="diagram" width="100%" height="580px" [contextMenuSettings]="contextMenuSettings" (contextMenuBeforeItemRender)="contextMenuBeforeItemRender($event)" (contextMenuOpen)="contextMenuOpen($event)" (contextMenuClick)="contextMenuClick($event)">
<e-nodes>
<e-node id='node1' [offsetX]=100 [offsetY]=100>
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle1" [width]=100 [height]=100>
</e-node-annotation>
</e-node-annotations>
</e-node>
<e-node id='node2' [offsetX]=300 [offsetY]=100 [width]=100 [height]=100>
<e-node-annotations>
<e-node-annotation id="label1" content="Rectangle2" >
</e-node-annotation>
</e-node-annotations>
</e-node>
</e-nodes>
<e-connectors>
<e-connector id='connector' type='Orthogonal' sourceID='node1' targetID='node2'>
</e-connector>
</e-connectors>
</ejs-diagram>`,
encapsulation: ViewEncapsulation.None
})
export class AppComponent {
@ViewChild("diagram")
public diagram?: DiagramComponent;
public contextMenuSettings?: ContextMenuSettingsModel;
ngOnInit(): void {
//Enables the context menu
this.contextMenuSettings = {
//Enables the context menu
show: true,
items: [
{
text: 'menu item 1',
id: 'item1',
},
{
text: 'menu item 2',
id: 'item2'
},
],
// Hides the default context menu items
showCustomMenuOnly: true,
} as ContextMenuSettingsModel;
}
public contextMenuBeforeItemRender(args: MenuEventArgs): void {
//Triggers for each menu item
console.log('context menu before item render');
}
public contextMenuOpen(args: DiagramBeforeMenuOpenEventArgs): void {
//Triggers when the menu is openned
console.log('context menu openned');
}
public contextMenuClick(args: MenuEventArgs): void {
//Triggers when the item is clicked
console.log('context menu clicked');
}
}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));