DataGrid and TreeList Issues
This section describes issues related to DataGrid and TreeList. If the solutions listed here do not help you resolve an issue, create a ticket in our Support Center and describe the issue in greater detail: Create a ticket.
Editors Values are not Saved
If an editor does not pass its value to the DataGrid or TreeList component and its DataSource when users enter or select a value, check if any of the following cases applies to your implementation.
A Column's dataField is Empty
Built-in column editors automatically write their values to the data row field specified in the column.dataField property. Specify this property if you want to write an editor's value to a field.
If you want to implement an unbound column, specify column.name instead of column.dataField and define the column.setCellValue callback to write values in a custom way.
jQuery
$('#gridContainer').dxDataGrid({ // ... columns: [ { // ... setCellValue(newData, value, currentRowData) { newData.anyField = value; } } ] });
Angular
<dx-data-grid ... > <dxi-column ... [setCellValue]="setCellValue" > </dxi-column> </dx-data-grid>
export class AppComponent { export class AppComponent { setCellValue(newData, value, currentRowData) { newData.anyField = value; } } }
Vue
<template> <DxDataGrid ... > <DxColumn ... :set-cell-value="setCellValue" /> </DxDataGrid> </template> <script> import { DxDataGrid, DxColumn } from 'devextreme-vue/data-grid'; export default { components: { DxDataGrid, DxColumn }, // ... methods: { setCellValue(newData, value, currentRowData) { newData.anyField = value; } } }; </script>
React
import React from 'react'; import DataGrid, { Column } from 'devextreme-react/data-grid'; const setCellValue = (newData, value, currentRowData) => { newData.anyField = value; } function App() { render ( <React.Fragment> <DataGrid ... > <Column ... setCellValue={setCellValue} /> </DataGrid> </React.Fragment> ); } export default App;
You Use a Form Item's Template to Declare an Editor
Form and popup edit modes use the built-in Form component. Do not use simpleItem.template to replace default editors in DataGrid or TreeList, use column.editCellTemplate instead.
You Implement an Editor in the editCellTemplate Body
Call the e.setValue method available in the template's argument. This method notifies the DataGrid or TreeList component that the value of a custom editor has changed. If you use a DevExtreme editor in this template, call e.setValue inside the onValueChanged event handler of this editor.
Customize Editors in DataGrid Demo
You Implement an Editor in the cellTemplate Body
DataGrid or TreeList uses column.cellTemplate only to display a cell value. To place your custom editor into cells to allow users to edit them, use column.editCellTemplate. Refer to the previous topic section for more information.
If you want to always display editors in a column, enable the column.showEditorAlways option. DataGrid displays an editor (or editCellTemplate if it exists) and ignores cellTemplate.
You Handle the editorPreparing Event and Override onValueChanged
Call the built-in onValueChanged event handler for an editor or call the e.setValue
method available in the event's argument.
jQuery
$('#gridContainer').dxDataGrid({ // ... onEditorPreparing(e) { if (e.dataField === 'requiredDataField' && e.parentType === 'dataRow') { const defaultValueChangeHandler = e.editorOptions.onValueChanged; e.editorOptions.onValueChanged = function (args) { e.setValue(args.value); // or defaultValueChangeHandler(args); } } } });
Angular
<dx-data-grid ... (onEditorPreparing)="onEditorPreparing($event)" > </dx-data-grid>
export class AppComponent { export class AppComponent { onEditorPreparing(e) { if (e.dataField === 'requiredDataField' && e.parentType === 'dataRow') { const defaultValueChangeHandler = e.editorOptions.onValueChanged; e.editorOptions.onValueChanged = function (args) { e.setValue(args.value); // or defaultValueChangeHandler(args); } } } } }
Vue
<template> <DxDataGrid ... @editor-preparing="onEditorPreparing" /> </template> <script> import { DxDataGrid } from 'devextreme-vue/data-grid'; export default { components: { DxDataGrid }, // ... methods: { onEditorPreparing(e) { if (e.dataField === 'requiredDataField' && e.parentType === 'dataRow') { const defaultValueChangeHandler = e.editorOptions.onValueChanged; e.editorOptions.onValueChanged = function (args) { e.setValue(args.value); // or defaultValueChangeHandler(args); } } } } }; </script>
React
import React from 'react'; import DataGrid from 'devextreme-react/data-grid'; onEditorPreparing = (e) => { if (e.dataField === 'requiredDataField' && e.parentType === 'dataRow') { const defaultValueChangeHandler = e.editorOptions.onValueChanged; e.editorOptions.onValueChanged = function (args) { e.setValue(args.value); // or defaultValueChangeHandler(args); } } } function App() { render ( <React.Fragment> <DataGrid ... onEditorPreparing={onEditorPreparing} /> </React.Fragment> ); } export default App;
See Also
Gray Boxes Appear After Data Loading
In certain cases, gray boxes may remain visible after DataGrid or TreeList finishes loading data:
These gray boxes are row placeholders that appear while the component loads and renders rows. These placeholders can remain visible in the following cases:
- The component size does not match the container size.
- An error occurs during data loading.
- Loaded data is incorrect (has wrong structure, missing required fields, the number of loaded items is not expected, etc.)
- Unexpected external interactions (when the component is re-rendering, the container is resized, the saved component state is corrupted, etc.)
Follow the steps below to troubleshoot your application. If the solutions listed here do not help you resolve an issue, create a ticket in our Support Center and describe the issue in greater detail: Create a ticket.
Use the Latest Version
jQuery
Update the devextreme
package to the latest version for quick testing. The issue may be resolved in the most recent update. Do not forget to back up the existing project. If you upgrade between major versions, follow the instructions in the following topic: Migrate to the New Version.
Angular
Update devextreme
and devextreme-angular
packages to the latest version for quick testing. The issue may be resolved in the most recent update. Do not forget to back up the existing project. If you upgrade between major versions, follow the instructions in the following topic: Migrate to the New Version.
Vue
Update devextreme
and devextreme-vue
packages to the latest version for quick testing. The issue may be resolved in the most recent update. Do not forget to back up the existing project. If you upgrade between major versions, follow the instructions in the following topic: Migrate to the New Version.
React
Update devextreme
and devextreme-react
packages to the latest version for quick testing. The issue may be resolved in the most recent update. Do not forget to back up the existing project. If you upgrade between major versions, follow the instructions in the following topic: Migrate to the New Version.
Ensure Component Size Matches Container Size
The component displays placeholders based on its height property and the number of loaded rows. If the height property value does not match the component's container size, the component does not load enough rows to fill the available area. The remaining area is filled with gray boxes.
If no parent element of the DataGrid or TreeList component has a fixed height, the component cannot calculate its size correctly. If the height of component's parent is relative, make sure that the parent's ancestor has a fixed height. If multiple ancestors have relative heights, at least one of them should have a fixed height.
If you wish to fill the entire container area by height and, therefore, do not use fixed heights, set the height of all parents (including <html>
) to 100%
.
If you use the component inside ScrollView, set the height of DataGrid or TreeList to a fixed value.
The DataGrid or TreeList component does not track its container size. If the container size changes, call the repaint() or updateDimensions() method. The following guide describes this issue in greater detail: Components are Rendered Incorrectly if a Container State is Changed.
Ensure Component is Correctly Bound to Data Source
Check if an error occurs during data loading (see Check Console for Warnings or Errors). Then, check if the component loads correct data (see Check Requests in the Network Tab). If you expect raw data, an array of records is sufficient. If you enable remote operations, check the required data structure in the following topic: Server-Side Data Processing.
Some data shaping operations may make data inconsistent. For instance, in the following code snippet, the postProcess function returns the number of data rows that do not match the total count parameter. As a result, gray boxes appear:
jQuery
const dataSource = new DevExpress.data.DataSource({ store: myStore, postProcess (data) { let filteredData = data.filter(condition); return filteredData; } });
Angular
import DataSource from "devextreme/data/data_source"; // ... export class AppComponent { ds: DataSource; constructor() { this.ds = new DataSource({ store: myStore, postProcess (data) { let filteredData = data.filter(condition); return filteredData; } }); } }
Vue
<script> import DataSource from 'devextreme/data/data_source'; const ds = new DataSource({ store: myStore, postProcess (data) { let filteredData = data.filter(condition); return filteredData; } }); export default { // ... data() { return { ds } } } </script>
React
// ... import DataSource from 'devextreme/data/data_source'; const ds = new DataSource({ store: myStore, postProcess (data) { let filteredData = data.filter(condition); return filteredData; } }); function App() { // ... } export default App;
To resolve the issue, remove the postProcess function or change it to return an array with the same number of items as the total count parameter. For more information about data filtering, refer to the following article: DataGrid Filtering API.
Eliminate Side Effects
Follow the steps below to eliminate possible side effects:
Disable the stateStoring property. Check if the issue still persists. If the issue disappears, it is possible that the saved state is corrupted. Clear the saved state, enable stateStoring, and check again.
FireFox and Safari browsers raise native scrolling events asynchronously. This behavior forces asynchronous row rendering in native scrolling mode even when renderAsync is disabled. To avoid this side effect, disable the scrolling.useNative property. Call the defaultOptions(rule) method to resolve the issue for all DataGrid components in the application.
If you bind DataGrid or TreeList to one DataSource instance, reset the DataSource page index once you destroy the component. DataSource does not reset the index automatically. A new component bound to this DataSource may attempt to display the first data page while DataSource may contain only other data pages. The component displays gray boxes in such case. Call the DataSource.pageIndex(newIndex) method to reset the page index.
Angular
If you use conditional rendering to display DataGrid or TreeList, and virtual scrolling is enabled, the following happens:
on hide
The scroll position is discarded.on show
The scroll position is set to the first page.
If DataGrid or TreeList was opened, for example, on the page 5 before it was hidden, the gray boxes are displayed after the component is shown for the second time. This happens because the data source is loaded for the page 5 only.
In such cases, save the scroll position on hide and restore it on show:
app.component.tsexport class AppComponent { // ... onContentVisibilityChange(visible) { if (!visible) { this.gridScrollPosition = this.dataGrid.instance.getScrollable().scrollTop(); } else if (this.gridScrollPosition > 0) { this.dataGrid.instance.getScrollable().scrollTo({ top: this.gridScrollPosition }); } }
Alternatively, you can use CSS to hide the component. In this case, call the updateDimensions method.
Vue
If you use conditional rendering to display DataGrid or TreeList, and virtual scrolling is enabled, the following happens:
on hide
The scroll position is discarded.on show
The scroll position is set to the first page.
If DataGrid or TreeList was opened, for example, on page 5 before it was hidden, the gray boxes are displayed after the component is shown for the second time. This happens because the data source is loaded for page 5 only.
In such cases, save the scroll position on hide and restore it on show:
App.vue<script> export default { // ... methods: { onContentVisibilityChange(visible) { if (!visible) { this.gridScrollPosition = this.dataGrid.instance.getScrollable().scrollTop(); } else if (this.gridScrollPosition > 0) { this.dataGrid.instance.getScrollable().scrollTo({ top: this.gridScrollPosition }); } } } } </script>
Alternatively, you can use CSS to hide the component. In this case, call the updateDimensions method.
React
In certain cases, row placeholders appear due to redundant re-rendering. To learn more about such issues, refer to the following guide: Optimize Performance.
If you use conditional rendering to display DataGrid or TreeList, and virtual scrolling is enabled, the following happens:
on hide
The scroll position is discarded.on show
The scroll position is set to the first page.
If DataGrid or TreeList was opened, for example, on page 5 before it was hidden, the gray boxes are displayed after the component is shown for the second time. This happens because the data source is loaded for page 5 only.
In such cases, save the scroll position on hide and restore it on show:
App.jsonContentVisibilityChange(visible) { if (!visible) { this.gridScrollPosition = this.dataGrid.instance.getScrollable().scrollTop(); } else if (this.gridScrollPosition > 0) { this.dataGrid.instance.getScrollable().scrollTo({ top: this.gridScrollPosition }); } } function App() { // ... } export default App;
Alternatively, you can use CSS to hide the component. In this case, call the updateDimensions method.
If you have technical questions, please create a support ticket in the DevExpress Support Center.
We appreciate your feedback.