JavaScript/jQuery Diagram - Restrict Operations

The Diagram UI component raises the requestEditOperation event every time a user attempts an edit operation. This article contains code samples that demonstrate how to use this event's parameters to prohibit individual edit operations and customize a shape collection in the toolbox and context toolbox.

Refer to the following section for more information on the requestEditOperation event's parameters: Prohibit Individual Operations.

Prohibit Creating Loops

The example below demonstrates how to prevent users from connecting a shape to itself:

app.component.html
app.component.ts
  • <dx-diagram #diagram id="diagram" (onRequestEditOperation)="requestEditOperationHandler($event)">
  • </dx-diagram>
  • import { Component, ViewChild} from '@angular/core';
  • import { DxDiagramModule, DxDiagramComponent } from 'devextreme-angular';
  •  
  • @Component({
  • selector: 'app-root',
  • templateUrl: './app.component.html',
  • styleUrls: ['./app.component.css']
  • })
  •  
  • export class AppComponent {
  • @ViewChild(DxDiagramComponent, { static: false }) diagram: DxDiagramComponent;
  • requestEditOperationHandler(e) {
  • if (e.operation === "changeConnection")
  • if (e.args.connector && e.args.connector.fromId === e.args.connector.toId)
  • e.allowed = false;
  • }
  • }

Prohibit Adding Shapes Twice

The example below demonstrates how to prevent users from adding more than one shape of each type to a chart:

app.component.html
app.component.ts
  • <dx-diagram #diagram id="diagram" (onRequestEditOperation)="requestEditOperation($event)">
  • </dx-diagram>
  • import { Component, ViewChild} from '@angular/core';
  • import { DxDiagramModule, DxDiagramComponent } from 'devextreme-angular';
  •  
  • @Component({
  • selector: 'app-root',
  • templateUrl: './app.component.html',
  • styleUrls: ['./app.component.css']
  • })
  •  
  • export class AppComponent {
  • @ViewChild(DxDiagramComponent, { static: false }) diagram: DxDiagramComponent;
  • requestEditOperation(e) {
  • if (e.operation === 'addShape') {
  • // Gets types of shapes the chart contains
  • var itemsTypes = e.component.getItems().filter(function(item) {
  • return (item.itemType === "shape") && (item.id !== e.args.shape.id);
  • }).map(a => a.type);
  • // Cancels the operation if the chart contains a shape with the same type as the shape that is about to be added
  • if (itemsTypes.indexOf(e.args.shape.type) !== -1) {
  • e.allowed = false;
  • return;
  • }
  • }
  • }
  • }
See Also

Remove Shapes from Toolboxes

In the example below, the Diagram component updates the shape collection in the toolbox and context toolbox as follows:

  • Removes a shape from these toolboxes after a user adds it to a chart
  • Returns a shape to these toolboxes after a user deletes it from a chart
app.component.html
app.component.ts
  • <dx-diagram #diagram id="diagram" (onOptionChanged)="optionChanged($event)" (onRequestEditOperation)="requestEditOperation($event)">
  • </dx-diagram>
  • import { Component, ViewChild} from '@angular/core';
  • import { DxDiagramModule, DxDiagramComponent } from 'devextreme-angular';
  •  
  • @Component({
  • selector: 'app-root',
  • templateUrl: './app.component.html',
  • styleUrls: ['./app.component.css']
  • })
  •  
  • export class AppComponent {
  • @ViewChild(DxDiagramComponent, { static: false }) diagram: DxDiagramComponent;
  • shapeCount: any;
  • optionChanged(e) {
  • // Detects changes of the Diagram model
  • if (e.name === "hasChanges" && e.value) {
  • e.component.option("hasChanges", false);
  • var currentShapeCount = e.component.getItems().filter(function(item) {
  • return (item.itemType ==="shape")
  • }).length;
  • // Updates the toolbox and context toolbox if a shape was added or deleted
  • if (this.shapeCount !== currentShapeCount) {
  • this.shapeCount = currentShapeCount;
  • window.setTimeout(function() {
  • e.component.updateToolbox();
  • }, 0);
  • }
  • }
  • }
  • requestEditOperation(e) {
  • if (e.operation === "addShapeFromToolbox") {
  • e.component.getItems().forEach(function(item) {
  • // Removes a shape from the toolboxes if the chart contains a shape of this type
  • if (item.itemType === "shape" && item.type === e.args.shapeType)
  • e.allowed = false;
  • });
  • }
  • }
  • }
See Also

Prohibit Moving Shapes Between Containers

The example below demonstrates how to prevent users from moving a shape from one container to another:

app.component.html
app.component.ts
  • <dx-diagram #diagram id="diagram" (onSelectionChanged)="selectionChanged($event)" (onRequestEditOperation)="requestEditOperation($event)">
  • </dx-diagram>
  • import { Component, ViewChild} from '@angular/core';
  • import { DxDiagramModule, DxDiagramComponent } from 'devextreme-angular';
  •  
  • @Component({
  • selector: 'app-root',
  • templateUrl: './app.component.html',
  • styleUrls: ['./app.component.css']
  • })
  •  
  • export class AppComponent {
  • @ViewChild(DxDiagramComponent, { static: false }) diagram: DxDiagramComponent;
  • containerIds: any = {};
  • requestEditOperation(e) {
  • if (e.operation === "moveShape")
  • // Cancels the operation if a user moves a shape outside its container.
  • if (this.containerIds[e.args.shape.id] !== e.args.shape.containerId)
  • e.allowed = false;
  • }
  • selectionChanged(e) {
  • e.component.getItems().forEach(item => {
  • this.containerIds[item.id] = item.containerId;
  • });
  • }
  • }

Customize Shape Collection in the Context Toolbox

The following example demonstrates how to hide shapes in the context toolbox depending on the connector's start node type:

app.component.html
app.component.ts
  • <dx-diagram #diagram id="diagram" (onRequestEditOperation)="requestEditOperation($event)">
  • <dxo-context-toolbox [enabled]="true" [shapes]='["process", "decision", "terminator"]' [shapeIconsPerRow]="3">
  • </dxo-context-toolbox>
  • </dx-diagram>
  • import { Component, ViewChild} from '@angular/core';
  • import { DxDiagramModule, DxDiagramComponent } from 'devextreme-angular';
  •  
  • @Component({
  • selector: 'app-root',
  • templateUrl: './app.component.html',
  • styleUrls: ['./app.component.css']
  • })
  •  
  • export class AppComponent {
  • @ViewChild(DxDiagramComponent, { static: false }) diagram: DxDiagramComponent;
  • currentShapeId : number;
  • requestEditOperation(e) {
  • if (e.operation === "changeConnection" && e.args.connector)
  • // Gets the connector's start node identifier
  • this.currentShapeId = e.args.connector.fromId;
  • if (e.operation === "addShapeFromToolbox") {
  • // Gets the connector's start node type
  • var currentShape = e.component.getItemById(this.currentShapeId);
  • if (e.args.shapeType === "terminator")
  • // If the connector's start node type is "decision"
  • if (currentShape && currentShape.type === "decision")
  • // Hides the "terminator" shape in the context toolbox
  • e.allowed = false;
  • }
  • }
  • }