Your search did not match any results.
Diagram

Templates with Editing

In this demo, the customShapeTemplate option defines a common shape template and adds the Edit and Delete links to a shape. These links allow users to modify and remove employee data from the data source. The Diagram widget reloads modified diagram data whenever the data source changes.

The onRequestLayoutUpdate function specifies whether the widget must reapply its auto layout once the diagram is reloaded.

The customDataExpr option links custom employee information from the data source to diagram nodes. Changes made to data are reflected in the diagram’s history. Undo and redo actions (available within the control’s UI) allow users to rollback/reapply changes.

The CustomShapeToolboxTemplate option specifies the template used for a shape within the toolbox.

@model IEnumerable<DevExtreme.NETCore.Demos.Models.OrgItemPlain> @(Html.DevExtreme().Diagram() .ID("diagram") .OnRequestLayoutUpdate("onRequestLayoutUpdate") .CustomShapes(cs => { cs.Add() .Type("employee") .Category("employee") .BaseType("rectangle") .Title("New Employee") .DefaultWidth(1.5) .DefaultHeight(1) .ToolboxWidthToHeightRatio(2) .MinWidth(1.5) .MinHeight(1) .MaxWidth(3) .MaxHeight(2) .AllowEditText(false); }) .CustomShapeTemplate(@<text> <svg class="template"> <text class="template-name" x="50%" y="20%"><%- dataItem ? dataItem.FullName : "Employee's Name" %></text> <text class="template-title" x="50%" y="45%"><%- dataItem ? dataItem.Title : "Employee's Title" %></text> <text class="template-button" x="40%" y="85%" onclick="editEmployee(<%- dataItem && JSON.stringify(dataItem) %>)">Edit</text> <text class="template-button" x="62%" y="85%" onclick="deleteEmployee(<%- dataItem && JSON.stringify(dataItem) %>)">Delete</text> </svg> </text>) .CustomShapeToolboxTemplate(@<text> <svg class="template"> <text x="50%" y="40%">New</text> <text x="50%" y="70%">Employee</text> </svg> </text>) .Nodes(ns => ns .DataSource(d => d .Array() .Key("ID") .Data(Model) .OnInserting("onNodeInserting") ) .KeyExpr("ID") .TypeExpr(new JS("itemTypeExpr")) .CustomDataExpr(new JS("itemCustomDataExpr")) .ParentKeyExpr("HeadID") .AutoLayout(al => al .Type(DiagramDataLayoutType.Tree) ) ) .ContextToolbox(ct => ct .ShapeIconsPerRow(1) .Width(100) ) .Toolbox(tb => tb .Groups(g => { g.Add().Category("employee").Title("Employee").Expanded(true); }) .ShowSearch(false) .ShapeIconsPerRow(1) ) .PropertiesPanel(pp => pp .Tabs(t => { t.Add() .Groups(g => { g.Add() .Title("Page Properties") .Commands(new[] { DiagramCommand.PageSize, DiagramCommand.PageOrientation, DiagramCommand.PageColor }); }); }) ) ) @(Html.DevExtreme().Popup() .ID("popup") .Width(400) .Height(480) .ShowTitle(true) .Title("Edit Employee") .Visible(false) .DragEnabled(false) .ContentTemplate(new TemplateName("popup-content")) ) @using(Html.DevExtreme().NamedTemplate("popup-content")) { <div class="dx-fieldset"> <div class="dx-field"> <div class="dx-field-label">Name</div> <div class="dx-field-value" data-field="FullName"> @(Html.DevExtreme().TextBox()) </div> </div> <div class="dx-field"> <div class="dx-field-label">Title</div> <div class="dx-field-value" data-field="Title"> @(Html.DevExtreme().TextBox()) </div> </div> <div class="dx-field"> <div class="dx-field-label">City</div> <div class="dx-field-value" data-field="City"> @(Html.DevExtreme().TextBox()) </div> </div> <div class="dx-field"> <div class="dx-field-label">State</div> <div class="dx-field-value" data-field="State"> @(Html.DevExtreme().TextBox()) </div> </div> <div class="dx-field"> <div class="dx-field-label">Email</div> <div class="dx-field-value" data-field="Email"> @(Html.DevExtreme().TextBox()) </div> </div> <div class="dx-field"> <div class="dx-field-label">Skype</div> <div class="dx-field-value" data-field="Skype"> @(Html.DevExtreme().TextBox()) </div> </div> <div class="dx-field"> <div class="dx-field-label">Phone</div> <div class="dx-field-value" data-field="MobilePhone"> @(Html.DevExtreme().TextBox()) </div> </div> </div> <div class="dx-fieldset buttons"> @(Html.DevExtreme().Button() .Text("Update") .Type(ButtonType.Default) .OnClick("updateEmployee") ) @(Html.DevExtreme().Button() .Text("Cancel") .OnClick("cancelEditEmployee") ) </div> } <script type="text/javascript"> var currentEmployee = {}; var generatedID = 100; function onNodeInserting(values) { values.ID = values.ID || generatedID++; values.FullName = values.FullName || "Employee's Name"; values.Title = values.Title || "Employee's Title"; } function itemTypeExpr(obj) { return "employee"; } function itemCustomDataExpr(obj, value) { if(value === undefined) { return { "FullName": obj.FullName, "Prefix": obj.Prefix, "Title": obj.Title, "City": obj.City, "State": obj.State, "Email": obj.Email, "Skype": obj.Skype, "MobilePhone": obj.MobilePhone }; } else { obj.FullName = value.FullName; obj.Prefix = value.Prefix; obj.Title = value.Title; obj.City = value.City; obj.State = value.State; obj.Email = value.Email; obj.Skype = value.Skype; obj.MobilePhone = value.MobilePhone; } } function onRequestLayoutUpdate(e) { for(var i = 0; i < e.changes.length; i++) { if(e.changes[i].type === 'remove') e.allowed = true; else if(e.changes[i].data.HeadID !== undefined && e.changes[i].data.HeadID !== null) e.allowed = true; } } function editEmployee(employee) { currentEmployee = Object.assign({}, employee); var popup = $("#popup").dxPopup("instance"); popup.show(); popup.content().find(".dx-field-value").each(function() { var field = $(this).attr("data-field"); var edit = $(this).children().dxTextBox("instance"); edit.option({ value: currentEmployee[field], onValueChanged: function(e) { handleChange(field, e.value); } }); }); }; function deleteEmployee(employee) { var diagram = $("#diagram").dxDiagram("instance"); diagram.getNodeDataSource().store().push([{ type: 'remove', key: employee.ID }]); }; function updateEmployee() { var diagram = $("#diagram").dxDiagram("instance"); diagram.getNodeDataSource().store().push([{ type: 'update', key: currentEmployee.ID, data: { "FullName": currentEmployee.FullName, "Title": currentEmployee.Title, "City": currentEmployee.City, "State": currentEmployee.State, "Email": currentEmployee.Email, "Skype": currentEmployee.Skype, "MobilePhone": currentEmployee.MobilePhone } }]); var popup = $("#popup").dxPopup("instance"); popup.hide(); }; function cancelEditEmployee() { currentEmployee = {}; var popup = $("#popup").dxPopup("instance"); popup.hide(); } function handleChange(field, value) { currentEmployee[field] = value; } </script>
using DevExtreme.NETCore.Demos.Models.SampleData; using Microsoft.AspNetCore.Mvc; namespace DevExtreme.NETCore.Demos.Controllers { public class DiagramController : Controller { public ActionResult CustomShapesWithTemplatesWithEditing() { return View(SampleData.OrgItemsPlain); } } }
#diagram { height: 725px; } #diagram .template .template-name { font-weight: bold; text-decoration: underline; } #diagram .template .template-title { font-style: italic; } #diagram .template .template-button { cursor: pointer; font-size: 8pt; fill: navy; } #diagram .template .template-button:hover { text-decoration: underline; } .dx-popup-content { padding: 0; } .dx-popup-content .dx-fieldset.buttons { display: flex; justify-content: flex-end; } .dx-popup-content .dx-fieldset.buttons > * { margin-left: 8px; }