Angular Diagram - Restrict Operations (2024)

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:

jQuery
$(function() { var diagram = $("#diagram").dxDiagram({ onRequestEditOperation: function(e) { if (e.operation === "changeConnection") if (e.args.connector && e.args.connector.fromId === e.args.connector.toId) e.allowed = false; }, }).dxDiagram("instance");});
Angular

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; }}
Vue
<template> <DxDiagram id="diagram" ref="diagram" @request-edit-operation="onRequestEditOperation"> </DxDiagram></template><script> import DxDiagram from 'devextreme-vue/diagram'; export default { components: { DxDiagram, }, methods: { onRequestEditOperation(e) { if (e.operation === "changeConnection") if (e.args.connector && e.args.connector.fromId === e.args.connector.toId) e.allowed = false; }, } };</script>
React
import React from 'react';import Diagram from 'devextreme-react/diagram';class App extends React.Component { constructor(props) { super(props); this.diagramRef = React.createRef(); this.onRequestEditOperation = this.onRequestEditOperation.bind(this); } onRequestEditOperation(e) { if (e.operation === 'changeConnection') if (e.args.connector && e.args.connector.fromId === e.args.connector.toId) e.allowed = false; } render() { return ( <Diagram id="diagram" ref={this.diagramRef} onRequestEditOperation={this.onRequestEditOperation}> </Diagram> ); }}export default App;

Prohibit Adding Shapes Twice

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

jQuery
$(function() { var diagram = $("#diagram").dxDiagram({ onRequestEditOperation(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; } } }, }).dxDiagram("instance");});
Angular

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; } } }}
Vue
<template> <DxDiagram id="diagram" ref="diagram" @request-edit-operation="onRequestEditOperation"> </DxDiagram></template><script> import DxDiagram from 'devextreme-vue/diagram'; export default { components: { DxDiagram }, methods: { onRequestEditOperation(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; } } }, } };</script>
React
import React from 'react';import Diagram, { ContextToolbox,} from 'devextreme-react/diagram';var currentShapeId;class App extends React.Component { constructor(props) { super(props); this.diagramRef = React.createRef(); this.onRequestEditOperation = this.onRequestEditOperation.bind(this); } onRequestEditOperation(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; } } } render() { return ( <Diagram id="diagram" ref={this.diagramRef} onRequestEditOperation={this.onRequestEditOperation} > </Diagram> ); }}export default App;
See Also
  • Remove Shapes from Toolboxes

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
jQuery
$(function () { var shapeCount = 0; var diagram = $("#diagram").dxDiagram({ onOptionChanged: function (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 (shapeCount !== currentShapeCount) { shapeCount = currentShapeCount; window.setTimeout(function() { e.component.updateToolbox(); }, 0); } } }, onRequestEditOperation(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; }); } }, }) .dxDiagram("instance");});
Angular

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; }); } }}
Vue
<template> <DxDiagram id="diagram" ref="diagram" @request-edit-operation="onRequestEditOperation" @option-changed="onOptionChanged"> </DxDiagram></template><script> import DxDiagram from 'devextreme-vue/diagram'; var shapeCount = 0; export default { components: { DxDiagram }, methods: { onOptionChanged(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); } } }, onRequestEditOperation(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; }); } }, } };</script>
React
import React from 'react';import Diagram from 'devextreme-react/diagram';var shapeCount;class App extends React.Component { constructor(props) { super(props); this.diagramRef = React.createRef(); this.onRequestEditOperation = this.onRequestEditOperation.bind(this); this.onOptionChanged = this.onOptionChanged.bind(this); } onOptionChanged(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); } } } onRequestEditOperation(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; }); } } render() { return ( <Diagram id="diagram" ref={this.diagramRef} onRequestEditOperation={this.onRequestEditOperation} onOptionChanged={this.onOptionChanged}> </Diagram> ); }}export default App;
See Also
  • Prohibit Adding Shapes Twice

Prohibit Moving Shapes Between Containers

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

jQuery
$(function() { var containerIds = {}; var diagram = $("#diagram").dxDiagram({ onRequestEditOperation: function(e) { if (e.operation === "moveShape") // Cancels the operation if a user moves a shape outside its container. if (containerIds[e.args.shape.id] !== e.args.shape.containerId) e.allowed = false; }, onSelectionChanged: function(e) { e.component.getItems().forEach(item => {containerIds[item.id] = item.containerId;}); }, }).dxDiagram("instance");});
Angular

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; }); }}
Vue
<template> <DxDiagram id="diagram" ref="diagram" @request-edit-operation="onRequestEditOperation" @selection-changed="onSelectionChanged"> </DxDiagram></template><script> import DxDiagram from 'devextreme-vue/diagram'; var containerIds = {}; export default { components: { DxDiagram }, methods: { onRequestEditOperation(e) { if (e.operation === "moveShape") // Cancels the operation if a user moves a shape outside its container. if (containerIds[e.args.shape.id] !== e.args.shape.containerId) e.allowed = false; }, onSelectionChanged(e) { e.component.getItems().forEach(item => {containerIds[item.id] = item.containerId;}); } }, };</script>
React
import React from 'react';import Diagram, from 'devextreme-react/diagram';var containerIds = {};class App extends React.Component { constructor(props) { super(props); this.diagramRef = React.createRef(); this.onRequestEditOperation = this.onRequestEditOperation.bind(this); this.onSelectionChanged = this.onSelectionChanged.bind(this); } onRequestEditOperation(e) { if (e.operation === "moveShape") // Cancels the operation if a user moves a shape outside its container. if (containerIds[e.args.shape.id] !== e.args.shape.containerId) e.allowed = false; } onSelectionChanged(e) { e.component.getItems().forEach(item => {containerIds[item.id] = item.containerId;}); } render() { return ( <Diagram id="diagram" ref={this.diagramRef} onRequestEditOperation={this.onRequestEditOperation} onSelectionChanged={this.onSelectionChanged}> </Diagram> ); }}export default App;

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:

jQuery
$(function() { var currentShapeId; var diagram = $("#diagram").dxDiagram({ onRequestEditOperation: function(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; } }, contextToolbox: { enabled: true, shapeIconsPerRow: 3, shapes: [ "process", "decision", "terminator" ], }, }) .dxDiagram("instance");});
Angular

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; } }}
Vue
<template> <DxDiagram id="diagram" ref="diagram" @request-edit-operation="onRequestEditOperation"> <DxContextToolbox :shape-icons-per-row="3" :width="100" :shapes="['process', 'decision', 'terminator']" /> </DxDiagram></template><script> import { DxDiagram, DxContextToolbox} from 'devextreme-vue/diagram'; var currentShapeId; export default { components: { DxDiagram, DxContextToolbox }, methods: { onRequestEditOperation(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; } } } };</script>
React
import React from 'react';import Diagram, { ContextToolbox,} from 'devextreme-react/diagram';var currentShapeId;class App extends React.Component { constructor(props) { super(props); this.diagramRef = React.createRef(); this.onRequestEditOperation = this.onRequestEditOperation.bind(this); } onRequestEditOperation(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; } } render() { return ( <Diagram id="diagram" ref={this.diagramRef} onRequestEditOperation={this.onRequestEditOperation} > <ContextToolbox shapeIconsPerRow={3} width={100} shapes={['process', 'decision', 'terminator']}> </ContextToolbox> </Diagram> ); }}export default App;

Was this topic helpful?

Feel free toshare topic-related thoughts here.
Ifyou have technical questions, please create asupport ticket inthe DevExpress Support Center.

Thank you for the feedback!

Angular Diagram - Restrict Operations (2024)
Top Articles
Latest Posts
Article information

Author: Velia Krajcik

Last Updated:

Views: 5846

Rating: 4.3 / 5 (54 voted)

Reviews: 93% of readers found this page helpful

Author information

Name: Velia Krajcik

Birthday: 1996-07-27

Address: 520 Balistreri Mount, South Armand, OR 60528

Phone: +466880739437

Job: Future Retail Associate

Hobby: Polo, Scouting, Worldbuilding, Cosplaying, Photography, Rowing, Nordic skating

Introduction: My name is Velia Krajcik, I am a handsome, clean, lucky, gleaming, magnificent, proud, glorious person who loves writing and wants to share my knowledge and understanding with you.