Your search did not match any results.
Data Grid

Real-Time Updates

The DataGrid widget is optimized for real-time updates. You should bind it to a DataSource that contains a store and use the push(changes) method to update the store's data. The rows with changed data are rerendered (see the DataGrid's repaintChangesOnly option). The DataSource object also provides options that control its behavior when it receives a push. For example, reshapeOnPush is set to true in this demo to allow summaries to be recalculated.

Grids in the detail sections are updated in real time as well. All the grids share the same ordersStore that receives pushes, but it is filtered to show only a specific product's orders for each grid.

Copy to CodeSandBox
Apply
Reset
<template> <div> <dx-data-grid :ref="dataGridRefName" :data-source="productsDataSource" :repaint-changes-only="true" :two-way-binding-enabled="false" :column-auto-width="true" :show-borders="true" > <dx-paging :page-size="10"/> <dx-column data-field="ProductName" data-type="string" /> <dx-column data-field="UnitPrice" data-type="number" format="currency" /> <dx-column data-field="OrderCount" data-type="number" /> <dx-column data-field="Quantity" data-type="number" /> <dx-column data-field="Amount" data-type="number" format="currency" /> <dx-summary> <dx-total-item column="ProductName" summary-type="count" /> <dx-total-item column="Amount" summary-type="sum" display-format="{0}" value-format="currency" /> <dx-total-item column="OrderCount" summary-type="sum" display-format="{0}" /> </dx-summary> <dx-master-detail :enabled="true" template="productDetail" /> <div slot="productDetail" slot-scope="{ data: detail }" > <dx-data-grid :data-source="getDetailGridDataSource(detail.data)" :column-auto-width="true" :repaint-changes-only="true" :two-way-binding-enabled="false" :show-borders="true" > <dx-paging :page-size="5"/> <dx-column data-field="OrderID" data-type="number" /> <dx-column data-field="ShipCity" data-type="string" /> <dx-column data-field="OrderDate" data-type="datetime" format="yyyy/MM/dd HH:mm:ss" /> <dx-column data-field="UnitPrice" data-type="number" format="currency" /> <dx-column data-field="Quantity" data-type="number" /> <dx-column :allow-sorting="true" :calculate-cell-value="getAmount" caption="Amount" format="currency" data-type="number" /> <dx-summary> <dx-total-item column="OrderID" summary-type="count" /> <dx-total-item column="Quantity" summary-type="sum" display-format="{0}" /> <dx-total-item column="Amount" summary-type="sum" display-format="{0}" value-format="currency" /> </dx-summary> </dx-data-grid> </div> </dx-data-grid> <div class="options"> <div class="caption">Options</div> <div class="option"> <span>Update frequency:</span> <dx-slider :min="10" :step="10" :max="5000" :value.sync="updatesPerSecond" > <dx-tooltip :enabled="true" format="#0 per second" show-mode="always" position="top" /> </dx-slider> </div> </div> </div> </template> <script> import { DxDataGrid, DxColumn, DxSummary, DxTotalItem, DxMasterDetail, DxPaging } from 'devextreme-vue/data-grid'; import { DxSlider, DxTooltip } from 'devextreme-vue/slider'; import { productsStore, ordersStore, getOrderCount, addOrder } from './data.js'; export default { components: { DxDataGrid, DxColumn, DxSummary, DxTotalItem, DxMasterDetail, DxPaging, DxSlider, DxTooltip }, data() { return { updatesPerSecond: 100, dataGridRefName: 'dataGrid', productsDataSource: { store: productsStore, reshapeOnPush: true } }; }, created() { setInterval(() => { if(getOrderCount() > 500000) { return; } for(var i = 0; i < this.updatesPerSecond / 20; i++) { addOrder(); } }, 50); }, methods: { getDetailGridDataSource(product) { return { store: ordersStore, reshapeOnPush: true, filter: ['ProductID', '=', product.ProductID] }; }, getAmount(order) { return order.UnitPrice * order.Quantity; } } }; </script> <style scoped> .options { padding: 20px; margin-top: 20px; background-color: rgba(191, 191, 191, 0.15); } .caption { font-size: 18px; font-weight: 500; } .option { margin-top: 10px; } .option > span { position: relative; top: 2px; margin-right: 10px; } .option > .dx-widget { width: 500px; display: inline-block; vertical-align: middle; } </style>
import Vue from 'vue'; import App from './App.vue'; new Vue({ el: '#app', components: { App }, template: '<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/19.1.4/css/dx.common.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/19.1.4/css/dx.light.css" /> <script src="https://unpkg.com/core-js@2.4.1/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"> <span v-if="false">Loading...</span> </div> </div> </body> </html>
import ArrayStore from 'devextreme/data/array_store'; const cities = ['Los Angeles', 'Denver', 'Bentonville', 'Atlanta', 'Reno', 'Beaver', 'Malibu', 'Phoenix', 'San Diego', 'Little Rock', 'Pasadena', 'Boise', 'San Jose', 'Chatsworth', 'San Fernando', 'South Pasadena', 'San Fernando Valley', 'La Canada', 'St. Louis']; const orders = []; const products = []; for(let i = 1; i <= 100; i++) { products.push({ ProductID: i, ProductName: `Product ${ i}`, UnitPrice: Math.floor(Math.random() * 1000) + 1, Quantity: 0, Amount: 0, OrderCount: 0 }); } export const productsStore = new ArrayStore({ key: 'ProductID', data: products }); export const ordersStore = new ArrayStore({ key: 'OrderID', data: orders }); export function getOrderCount() { return orders.length; } export function addOrder() { const product = products[Math.round(Math.random() * 99)]; const order = { OrderID: orders.length ? orders[orders.length - 1].OrderID + 1 : 20001, ShipCity: cities[Math.round(Math.random() * (cities.length - 1))], ProductID: product.ProductID, UnitPrice: product.UnitPrice, OrderDate: new Date(), Quantity: Math.round(Math.random() * 20) + 1 }; ordersStore.push([{ type: 'insert', data: order }]); productsStore.push([{ type: 'update', key: order.ProductID, data: { OrderCount: product.OrderCount + 1, Quantity: product.Quantity + order.Quantity, Amount: product.Amount + order.UnitPrice * order.Quantity } }]); }
System.config({ transpiler: 'plugin-babel', paths: { 'npm:': 'https://unpkg.com/' }, map: { vue: 'npm:vue@2.6.3/dist/vue.esm.browser.js', 'vue-loader': 'npm:systemjs-vue-browser@latest/index.js', 'devextreme': 'npm:devextreme@19.1', 'devextreme-vue': 'npm:devextreme-vue@19.1', jszip: 'npm:jszip@3.1.3/dist/jszip.min.js', 'quill': 'npm:quill@1.3.6/dist/quill.js', 'devexpress-diagram': 'npm:devexpress-diagram', 'plugin-babel': 'npm:systemjs-plugin-babel@0/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0/systemjs-babel-browser.js' }, meta: { '*.vue': { loader: 'vue-loader' } }, packages: { 'devextreme-vue': { main: 'index.js' }, 'devextreme': { defaultExtension: 'js' } }, babelOptions: { sourceMaps: false, stage0: true } });