All docs
V23.2
24.1
23.2
23.1
22.2
The page you are viewing does not exist in version 22.2.
22.1
The page you are viewing does not exist in version 22.1.
21.2
The page you are viewing does not exist in version 21.2.
21.1
The page you are viewing does not exist in version 21.1.
20.2
The page you are viewing does not exist in version 20.2.
20.1
The page you are viewing does not exist in version 20.1.
19.2
The page you are viewing does not exist in version 19.2.
19.1
The page you are viewing does not exist in version 19.1.
18.2
The page you are viewing does not exist in version 18.2.
18.1
The page you are viewing does not exist in version 18.1.
17.2
The page you are viewing does not exist in version 17.2.

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:

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

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 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;