CRUD Operations - Vue Data Grid (2024)

<template> <div> <DxDataGrid id="grid" :show-borders="true" :data-source="ordersData" :repaint-changes-only="true" > <DxEditing :refresh-mode="refreshMode" :allow-adding="true" :allow-updating="true" :allow-deleting="true" mode="cell" /> <DxColumn data-field="CustomerID" caption="Customer" > <DxLookup :data-source="customersData" value-expr="Value" display-expr="Text" /> </DxColumn> <DxColumn data-field="OrderDate" data-type="date" /> <DxColumn data-field="Freight"/> <DxColumn data-field="ShipCountry"/> <DxColumn data-field="ShipVia" caption="Shipping Company" data-type="number" > <DxLookup :data-source="shippersData" value-expr="Value" display-expr="Text" /> </DxColumn> <DxScrolling mode="virtual"/> <DxSummary> <DxTotalItem column="CustomerID" summary-type="count" /> <DxTotalItem column="Freight" summary-type="sum" value-format="#0.00" /> </DxSummary> </DxDataGrid> <div class="options"> <div class="caption">Options</div> <div class="option"> <span>Refresh Mode: </span> <DxSelectBox v-model:value="refreshMode" :input-attr="{ 'aria-label': 'Refresh Mode' }" :items="refreshModes" /> </div> <div id="requests"> <div> <div class="caption">Network Requests</div> <DxButton id="clear" text="Clear" @click="clearRequests" /> </div> <ul> <li v-for="(request, index) in requests" :key="index" >{{ request }}</li> </ul> </div> </div> </div></template><script setup lang="ts">import { ref } from 'vue';import { DxDataGrid, DxColumn, DxEditing, DxScrolling, DxSummary, DxLookup, DxTotalItem,} from 'devextreme-vue/data-grid';import { DxButton } from 'devextreme-vue/button';import { DxSelectBox } from 'devextreme-vue/select-box';import CustomStore from 'devextreme/data/custom_store';import { formatDate } from 'devextreme/localization';import 'whatwg-fetch';const URL = 'https://js.devexpress.com/Demos/Mvc/api/DataGridWebApi';const ordersData = new CustomStore({ key: 'OrderID', load: () => sendRequest(`${URL}/Orders`), insert: (values) => sendRequest(`${URL}/InsertOrder`, 'POST', { values: JSON.stringify(values), }), update: (key, values) => sendRequest(`${URL}/UpdateOrder`, 'PUT', { key, values: JSON.stringify(values), }), remove: (key) => sendRequest(`${URL}/DeleteOrder`, 'DELETE', { key, }),});const customersData = new CustomStore({ key: 'Value', loadMode: 'raw', load: () => sendRequest(`${URL}/CustomersLookup`),});const shippersData = new CustomStore({ key: 'Value', loadMode: 'raw', load: () => sendRequest(`${URL}/ShippersLookup`),});const refreshModes = ['full', 'reshape', 'repaint'];const requests = ref<string[]>([]);const refreshMode = ref('reshape');const sendRequest = async(url: string, method = 'GET', data: Record<string, string> = {}) => { logRequest(method, url, data); const request: any = { method, credentials: 'include', }; if (['DELETE', 'POST', 'PUT'].includes(method)) { const params = Object.keys(data) .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`) .join('&'); request.body = params; request.headers = { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }; } const response = await fetch(url, request); const isJson = response.headers.get('content-type')?.includes('application/json'); const result = isJson ? await response.json() : {}; if (!response.ok) { throw result.Message; } return method === 'GET' ? result.data : {};};const logRequest = (method: string, url: string, data: Record<string, string>) => { const args = Object.keys(data || {}).map((key) => `${key}=${data[key]}`).join(' '); const time = formatDate(new Date(), 'HH:mm:ss'); requests.value.unshift([time, method, url.slice(URL.length), args].join(' '));};const clearRequests = () => { requests.value = [];};</script><style scoped>#grid { height: 440px;}.options { padding: 20px; margin-top: 20px; background-color: rgba(191, 191, 191, 0.15);}.caption { margin-bottom: 10px; font-weight: 500; font-size: 18px;}.option { margin-bottom: 10px;}.option > span { position: relative; top: 2px; margin-right: 10px;}.option > .dx-widget { display: inline-block; vertical-align: middle;}#requests .caption { float: left; padding-top: 7px;}#requests > div { padding-bottom: 5px;}#requests > div::after { content: ""; display: table; clear: both;}#requests #clear { float: right;}#requests ul { list-style: none; max-height: 100px; overflow: auto; margin: 0;}#requests ul li { padding: 7px 0; border-bottom: 1px solid #ddd;}#requests ul li:last-child { border-bottom: none;}</style>

window.exports = window.exports || {};window.config = { transpiler: 'plugin-babel', meta: { '*.vue': { loader: 'vue-loader', }, '*.ts': { loader: 'demo-ts-loader', }, '*.svg': { loader: 'svg-loader', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, }, paths: { 'root:': '../../../../../', 'npm:': 'https://unpkg.com/', }, map: { 'vue': 'npm:vue@3.3.4/dist/vue.esm-browser.js', 'vue-loader': 'npm:dx-systemjs-vue-browser@1.1.1/index.js', 'demo-ts-loader': 'root:utils/demo-ts-loader.js', 'svg-loader': 'root:utils/svg-loader.js', 'whatwg-fetch': 'npm:whatwg-fetch@2.0.4/fetch.js', 'mitt': 'npm:mitt/dist/mitt.umd.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.2.5/cjs', 'devextreme-vue': 'npm:devextreme-vue@23.2.5/cjs', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'devextreme-quill': 'npm:devextreme-quill@1.6.4/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.51/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12', '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', '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-vue': { main: 'index.js', }, 'devextreme': { defaultExtension: '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.12/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, },};System.config(window.config);

import { createApp } from 'vue';import App from './App.vue';createApp(App).mount('#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.2.5/css/dx.light.css" /> <script type="module"> import * as vueCompilerSFC from "https://unpkg.com/@vue/compiler-sfc@3.3.4/dist/compiler-sfc.esm-browser.js"; window.vueCompilerSFC = vueCompilerSFC; </script> <script src="https://unpkg.com/typescript@4.2.4/lib/typescript.js"></script> <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.ts"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app" /> </div> </body></html>

using DevExtreme.AspNet.Data;using DevExtreme.AspNet.Mvc;using Newtonsoft.Json;using System;using System.Linq;using System.Net;using System.Net.Http;using System.Net.Http.Formatting;using System.Web.Http;using DevExtreme.MVC.Demos.Models.Northwind;using DevExtreme.MVC.Demos.Models.DataGrid;using System.Collections.Generic;namespace DevExtreme.MVC.Demos.Controllers { [Route("api/DataGridWebApi/{action}", Name = "DataGridWebApi")] public class DataGridWebApiController : ApiController { InMemoryNorthwindContext _nwind = new InMemoryNorthwindContext(); [HttpGet] public HttpResponseMessage Orders(DataSourceLoadOptions loadOptions) { return Request.CreateResponse(DataSourceLoader.Load(_nwind.Orders, loadOptions)); } [HttpPost] public HttpResponseMessage InsertOrder(FormDataCollection form) { var values = form.Get("values"); var newOrder = new Order(); JsonConvert.PopulateObject(values, newOrder); Validate(newOrder); if(!ModelState.IsValid) return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState.GetFullErrorMessage()); _nwind.Orders.Add(newOrder); _nwind.SaveChanges(); return Request.CreateResponse(HttpStatusCode.Created, newOrder); } [HttpPut] public HttpResponseMessage UpdateOrder(FormDataCollection form) { var key = Convert.ToInt32(form.Get("key")); var values = form.Get("values"); var order = _nwind.Orders.First(o => o.OrderID == key); JsonConvert.PopulateObject(values, order); Validate(order); if(!ModelState.IsValid) return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState.GetFullErrorMessage()); _nwind.SaveChanges(); return Request.CreateResponse(HttpStatusCode.OK, order); } [HttpDelete] public void DeleteOrder(FormDataCollection form) { var key = Convert.ToInt32(form.Get("key")); var order = _nwind.Orders.First(o => o.OrderID == key); _nwind.Orders.Remove(order); _nwind.SaveChanges(); } // additional actions [HttpGet] public HttpResponseMessage OrderDetails(int orderID, DataSourceLoadOptions loadOptions) { return Request.CreateResponse(DataSourceLoader.Load( from i in _nwind.Order_Details where i.OrderID == orderID select new { Product = i.Product.ProductName, Price = i.UnitPrice, i.Quantity, Sum = i.UnitPrice * i.Quantity }, loadOptions )); } [HttpGet] public HttpResponseMessage ShippersLookup(DataSourceLoadOptions loadOptions) { var lookup = from i in _nwind.Shippers orderby i.CompanyName select new { Value = i.ShipperID, Text = i.CompanyName }; return Request.CreateResponse(DataSourceLoader.Load(lookup, loadOptions)); } [HttpGet] public HttpResponseMessage CustomersLookup(DataSourceLoadOptions loadOptions) { var lookup = from i in _nwind.Customers let text = i.CompanyName + " (" + i.Country + ")" orderby i.CompanyName select new { Value = i.CustomerID, Text = text }; return Request.CreateResponse(DataSourceLoader.Load(lookup, loadOptions)); } [HttpPost] public HttpResponseMessage Batch(List<DataChange> changes) { foreach(var change in changes) { Order order; if(change.Type == "update" || change.Type == "remove") { var key = Convert.ToInt32(change.Key); order = _nwind.Orders.First(o => o.OrderID == key); } else { order = new Order(); } if(change.Type == "insert" || change.Type == "update") { JsonConvert.PopulateObject(change.Data.ToString(), order); Validate(order); if(!ModelState.IsValid) return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState.GetFullErrorMessage()); if(change.Type == "insert") { _nwind.Orders.Add(order); } change.Data = order; } else if(change.Type == "remove") { _nwind.Orders.Remove(order); } } _nwind.SaveChanges(); return Request.CreateResponse(HttpStatusCode.OK, changes); } }}

using System;using System.Collections.Generic;using System.Data.Entity;namespace DevExtreme.MVC.Demos.Models.Northwind { public class InMemoryNorthwindContext : InMemoryDataContext<Order> { readonly NorthwindContext _nwind = new NorthwindContext(); public DbSet<Customer> Customers => _nwind.Customers; public DbSet<Order_Detail> Order_Details => _nwind.Order_Details; public ICollection<Order> Orders => ItemsInternal; public DbSet<Shipper> Shippers => _nwind.Shippers; protected override IEnumerable<Order> Source => _nwind.Orders; protected override int GetKey(Order item) => item.OrderID; protected override void SetKey(Order item, int key) => item.OrderID = key; }}

CRUD Operations - Vue Data Grid (2024)
Top Articles
Latest Posts
Article information

Author: Aracelis Kilback

Last Updated:

Views: 6443

Rating: 4.3 / 5 (64 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Aracelis Kilback

Birthday: 1994-11-22

Address: Apt. 895 30151 Green Plain, Lake Mariela, RI 98141

Phone: +5992291857476

Job: Legal Officer

Hobby: LARPing, role-playing games, Slacklining, Reading, Inline skating, Brazilian jiu-jitsu, Dance

Introduction: My name is Aracelis Kilback, I am a nice, gentle, agreeable, joyous, attractive, combative, gifted person who loves writing and wants to share my knowledge and understanding with you.