DevExtreme v23.1 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.
Diagram

Web API Service

Documentation

This example demonstrates the Diagram component communicating with a Web API service. All data editing and processing operations are delegated to the server. The DevExtreme.AspNet.Data extension's createStore method configures access to the server from the client. The server implementation is available under the DiagramEmployeesController.cs tab in the ASP.NET MVC version of this demo.

Backend API
Copy to CodeSandBox
Apply
Reset
import React from 'react'; import Diagram, { Nodes, AutoLayout, ContextToolbox, Toolbox, Group, } from 'devextreme-react/diagram'; import { createStore } from 'devextreme-aspnet-data-nojquery'; const url = 'https://js.devexpress.com/Demos/Mvc/api/DiagramEmployees'; const dataSource = createStore({ key: 'ID', loadUrl: `${url}/Employees`, insertUrl: `${url}/InsertEmployee`, updateUrl: `${url}/UpdateEmployee`, deleteUrl: `${url}/DeleteEmployee`, onBeforeSend(method, ajaxOptions) { ajaxOptions.xhrFields = { withCredentials: true }; }, onInserting(values) { values.ID = 0; values.Title = values.Title || 'New Position'; values.Prefix = 'Mr'; values.FullName = 'New Employee'; values.City = 'LA'; values.State = 'CA'; values.HireDate = new Date(); }, }); const shapes = ['rectangle']; class App extends React.Component { render() { return ( <Diagram id="diagram"> <Nodes dataSource={dataSource} keyExpr="ID" textExpr="Title" parentKeyExpr="HeadID"> <AutoLayout type="tree" /> </Nodes> <ContextToolbox shapeIconsPerRow={2} width={100} shapes={shapes}> </ContextToolbox> <Toolbox showSearch={false} shapeIconsPerRow={2}> <Group title="Items" shapes={shapes} /> </Toolbox> </Diagram> ); } } export default App;
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render( <App />, document.getElementById('app'), );
<!DOCTYPE html> <html> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/23.1.5/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/23.1.5/css/dx-diagram.css" /> <link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" /> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import("./index.js"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"></div> </div> </body> </html>
#diagram { height: 725px; }
window.config = { transpiler: 'plugin-babel', meta: { 'devextreme/localization.js': { 'esModule': true, }, 'devextreme-aspnet-data-nojquery': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', }, defaultExtension: 'js', map: { 'react': 'npm:react@17.0.2/umd/react.development.js', 'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js', 'prop-types': 'npm:prop-types@15.8.1/prop-types.js', 'devextreme-aspnet-data-nojquery': 'npm:devextreme-aspnet-data-nojquery@2.9.0/index.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@1.28.1/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign@1.1.0', 'devextreme': 'npm:devextreme@23.1.5/cjs', 'devextreme-react': 'npm:devextreme-react@23.1.5', 'jszip': 'npm:jszip@3.7.1/dist/jszip.min.js', 'devextreme-quill': 'npm:devextreme-quill@1.6.2/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.1/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.48/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.11', 'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate@7.4.11/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', // SystemJS plugins 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.4/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.4/parser-html.js', }, packages: { 'devextreme': { defaultExtension: 'js', }, 'devextreme-react': { main: 'index.js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.11/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, react: true, }, }; System.config(window.config);
using System; using System.Collections.Generic; namespace DevExtreme.MVC.Demos.Models.Diagram { public class InMemoryEmployeesDataContext : InMemoryDataContext<Employee> { public ICollection<Employee> Employees => ItemsInternal; protected override IEnumerable<Employee> Source => SampleData.SampleData.DiagramEmployees; protected override int GetKey(Employee item) => item.ID; protected override void SetKey(Employee item, int key) => item.ID = key; } }
using DevExtreme.AspNet.Data; using DevExtreme.AspNet.Mvc; using DevExtreme.MVC.Demos.Models.Diagram; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Formatting; using System.Web.Http; namespace DevExtreme.MVC.Demos.Controllers.ApiControllers { [Route("api/DiagramEmployees/{action}", Name = "DiagramEmployees")] public class DiagramEmployeesController : ApiController { InMemoryEmployeesDataContext db = new InMemoryEmployeesDataContext(); [HttpGet] public HttpResponseMessage Employees(DataSourceLoadOptions loadOptions) { return Request.CreateResponse(DataSourceLoader.Load(db.Employees, loadOptions)); } [HttpPost] public HttpResponseMessage InsertEmployee(FormDataCollection form) { var values = form.Get("values"); var newEmployee = new Employee(); JsonConvert.PopulateObject(values, newEmployee); Validate(newEmployee); if(!ModelState.IsValid) return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState.GetFullErrorMessage()); db.Employees.Add(newEmployee); db.SaveChanges(); return Request.CreateResponse(HttpStatusCode.Created, newEmployee); } [HttpPut] public HttpResponseMessage UpdateEmployee(FormDataCollection form) { var key = Convert.ToInt32(form.Get("key")); var values = form.Get("values"); var employee = db.Employees.First(e => e.ID == key); JsonConvert.PopulateObject(values, employee); Validate(employee); if(!ModelState.IsValid) return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState.GetFullErrorMessage()); db.SaveChanges(); return Request.CreateResponse(HttpStatusCode.OK, employee); } [HttpDelete] public void DeleteEmployee(FormDataCollection form) { var key = Convert.ToInt32(form.Get("key")); var employee = db.Employees.First(e => e.ID == key); db.Employees.Remove(employee); db.SaveChanges(); } } }