An object defining configuration properties for the TreeList UI component.
Specifies the shortcut key that sets focus on the UI component.
The value of this property will be passed to the accesskey
attribute of the HTML element that underlies the UI component.
Specifies whether the UI component changes its visual state as a result of user interaction.
The UI component switches to the active state when users press down the primary mouse button. When this property is set to true, the CSS rules for the active state apply. You can change these rules to customize the component.
Use this property when you display the component on a platform whose guidelines include the active state change for UI components.
Specifies whether a user can reorder columns.
Initially, columns appear in the order specified by the columns array. If you skip specifying this array, columns will mirror the order of fields in the first object from the dataSource. You can allow a user to reorder columns at runtime by setting the allowColumnReordering property to true.
See AlsoSpecifies whether a user can resize columns.
Specifies whether all rows are expanded.
Automatically scrolls the component to the focused row when the focusedRowKey is changed.
You must specify the component's
heightto ensure that the
autoNavigateToFocusedRowproperty works properly.
If you set the remoteOperations property to true, the TreeList generates additional requests with comparison operators (for example, <
and >
). This logic does not work if ODataStore is bound to a table with GUID keys. You need to disable the autoNavigateToFocusedRow or remoteOperations properties to ensure it operates correctly.
Specifies whether data should be cached.
When this property is set to true, data loaded once is saved in cache. Then, the UI component takes data from this cache when performing such operations as sorting, grouping, paging, etc. Caching is helpful when the data source takes significant time to load. But, consider disabling it for frequently changing data sources.
To update data in cache, call the refresh() method of the UI component or the reload() method of the DataSource:
jQuery$("#treeListContainer").dxTreeList("refresh"); // ===== or ===== const treeListDataSource = $("#treeListContainer").dxTreeList("getDataSource"); treeListDataSource.reload();Angular
import { ..., ViewChild } from "@angular/core"; import { DxTreeListModule, DxTreeListComponent } from "devextreme-angular"; // ... export class AppComponent { @ViewChild(DxTreeListComponent, { static: false }) treeList: DxTreeListComponent; // Prior to Angular 8 // @ViewChild(DxTreeListComponent) treeList: DxTreeListComponent; refreshData () { this.treeList.instance.refresh(); // ===== or ===== const treeListDataSource = this.treeList.instance.getDataSource(); treeListDataSource.reload(); } } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })Vue
<template> <DxTreeList :ref="treeListRefKey"> <!-- ... --> </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList from 'devextreme-vue/tree-list'; const treeListRefKey = "my-tree-list"; export default { components: { DxTreeList }, data() { return { treeListRefKey } }, methods: { refreshData() { this.treeList.refresh(); // ===== or ===== const treeListDataSource = this.treeList.getDataSource(); treeListDataSource.reload(); } }, computed: { treeList: function() { return this.$refs[treeListRefKey].instance; } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-react/tree-list'; class App extends React.Component { constructor(props) { super(props); this.treeListRef = React.createRef(); this.refreshData = () => { this.treeList.refresh(); // ===== or ===== const treeListDataSource = this.treeList.getDataSource(); treeListDataSource.reload(); } } get treeList() { return this.treeListRef.current.instance(); } render() { return ( <TreeList ref={this.treeListRef}> {/* ... */ } </TreeList> ); } } export default App;
Enables a hint that appears when a user hovers the mouse pointer over a cell with truncated content.
The cell's content may be truncated if the width of the cell's column becomes very small. In this case, when a user hovers the mouse pointer over such a cell, a hint containing the cell's value appears. To disable cell hints, assign false to the cellHintEnabled property.
Specifies whether columns should adjust their widths to the content.
When this property is set to true, all columns adjust their width to the content.
If the TreeList is wider than its overall content, the columns are stretched to occupy all available width. To avoid this, set the columnWidth or columns.width property to "auto".
If the content is wider, the columnAutoWidth property set to true causes horizontal scrolling. You can set the allowHiding property to false for columns you want to be displayed continuously.
When the columnAutoWidth property is set to false, all columns have identical width, which in turn depends on the width of the UI component.
See AlsoConfigures the column chooser.
Configures column fixing.
When the width of all columns exceeds the UI component width, horizontal scrolling appears. If specific columns should be on screen constantly regardless of how far the UI component is scrolled, allow a user to fix them at runtime using the context menu. For this, set the columnFixing.enabled property to true.
When you enable column fixing, command columns become fixed automatically.
See AlsoSpecifies the minimum width of columns.
Specifies how the UI component resizes columns. Applies only if allowColumnResizing is true.
Default Value: 'nextColumn'
The columnResizingMode property accepts one of the following values:
If this property is set to
'nextColumn'
(default) and you enable the
columnHidingEnabledproperty, then also enable
columnAutoWidthto ensure the component works properly.
Configures columns.
Selector: Column
Default Value: undefined
This property accepts an array of objects, where each object configures a single column. If a column does not need to be customized, this array may include the name of the field that provides data for this column.
jQuery$(function() { $("#treeListContainer").dxTreeList({ // ... columns: [{ dataField: "Title", caption: "Position" }, { dataField: "FullName", width: 300 }, "CompanyName", "City" ] }); });Angular
<dx-tree-list ... > <dxi-column dataField="Title" caption="Position"></dxi-column> <dxi-column dataField="FullName" [width]="300"></dxi-column> <dxi-column dataField="CompanyName"></dxi-column> <dxi-column dataField="City"></dxi-column> </dx-tree-list>
import { DxTreeListModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })Vue
<template> <DxTreeList ... > <DxColumn data-field="Title" caption="Position" /> <DxColumn data-field="FullName" :width="300" /> <DxColumn data-field="CompanyName" /> <DxColumn data-field="City" /> </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList, { DxColumn } from 'devextreme-vue/tree-list'; export default { components: { DxTreeList, DxColumn }, // ... } </script>React
import 'devextreme/dist/css/dx.light.css'; import TreeList, { Column } from 'devextreme-react/tree-list'; export default function App() { return ( <TreeList> <Column dataField="Title" caption="Position" /> <Column dataField="FullName" width={300} /> <Column dataField="CompanyName" /> <Column dataField="City" /> </TreeList> ); }See Also
Specifies the width for all data columns. Has a lower priority than the column.width property.
Customizes columns after they are created.
Use this function to make minor adjustments to automatically generated columns. You can access and modify column configurations using the function's parameter.
jQuery$(function(){ $("#treeList").dxTreeList({ // ... customizeColumns: function (columns) { columns[0].width = 100; columns[1].width = 210; } }) });Angular
import { DxTreeListModule } from "devextreme-angular"; // ... export class AppComponent { customizeColumns (columns) { columns[0].width = 100; columns[1].width = 210; } } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })
<dx-tree-list ... [customizeColumns]="customizeColumns"> </dx-tree-list>Vue
<template> <DxTreeList ... :customize-columns="customizeColumns"> /> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList, { // ... } from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, methods: { customizeColumns(columns) { columns[0].width = 100; columns[1].width = 210; } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList, { // ... } from 'devextreme-react/tree-list'; class App extends React.Component { customizeColumns = (columns) => { columns[0].width = 100; columns[1].width = 210; } render() { return ( <TreeList ... customizeColumns={this.customizeColumns} /> ); } } export default App;ASP.NET MVC Controls
@(Html.DevExtreme().TreeList() // ... .CustomizeColumns("customizeColumns") ) <script> function customizeColumns(columns) { columns[0].width = 100; columns[1].width = 210; } </script>
Data operations (sorting, filtering, summary) are unavailable for the columns created via
customizeColumns. To create a fully functioning column, add it to the
columnsarray.
ReactNote that the [elementName]Render and [elementName]Component (for example, the cellRender and cellComponent) do not work within the customizeColumn function. Instead, use the columns array.
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList, { // ... } from 'devextreme-react/tree-list'; class App extends React.Component { customizeColumns = (columns) => { // ... // This code does not work // columns[0].cellRender = cellRender; } render() { return ( <TreeList ... customizeColumns={this.customizeColumns} > <!-- ... --> <Column dataField="Picture" cellRender={cellRender} <!-- This code works correctly --> /> </TreeList> ); } } function cellRender(data) { return <img src={data.value} />; } export default App;
Binds the UI component to data.
The TreeList works with object collections that can have a plain or hierarchical structure. Depending on the structure, the objects should provide different data fields. Specify the dataStructure property to notify the TreeList of the used structure and refer to the property's description for information on the required fields.
Depending on your data source, bind TreeList to data as follows.
Data Array
Assign the array to the dataSource option. View Demo
Read-Only Data in JSON Format
Set the dataSource property to the URL of a JSON file or service that returns JSON data.
OData
Implement an ODataStore.
Web API, PHP, MongoDB
Use one of the following extensions to enable the server to process data according to the protocol DevExtreme UI components use:
Then, use the createStore method to configure access to the server on the client as shown below. This method is part of DevExtreme.AspNet.Data.
jQuery$(function() { let serviceUrl = "https://url/to/my/service"; $("#treeListContainer").dxTreeList({ // ... dataSource: DevExpress.data.AspNet.createStore({ key: "ID", loadUrl: serviceUrl + "/GetAction", insertUrl: serviceUrl + "/InsertAction", updateUrl: serviceUrl + "/UpdateAction", deleteUrl: serviceUrl + "/DeleteAction" }) }) });Angular
import { Component } from '@angular/core'; import CustomStore from 'devextreme/data/custom_store'; import { createStore } from 'devextreme-aspnet-data-nojquery'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { store: CustomStore; constructor() { let serviceUrl = "https://url/to/my/service"; this.store = createStore({ key: "ID", loadUrl: serviceUrl + "/GetAction", insertUrl: serviceUrl + "/InsertAction", updateUrl: serviceUrl + "/UpdateAction", deleteUrl: serviceUrl + "/DeleteAction" }) } }
<dx-tree-list ... [dataSource]="store"> </dx-tree-list>
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { DxTreeListModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, DxTreeListModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }Vue
<template> <DxTreeList ... :data-source="store" /> </template> <script> import 'devextreme/dist/css/dx.light.css'; import CustomStore from 'devextreme/data/custom_store'; import { createStore } from 'devextreme-aspnet-data-nojquery'; import { DxTreeList } from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, data() { const serviceUrl = "https://url/to/my/service"; const store = createStore({ key: "ID", loadUrl: serviceUrl + "/GetAction", insertUrl: serviceUrl + "/InsertAction", updateUrl: serviceUrl + "/UpdateAction", deleteUrl: serviceUrl + "/DeleteAction" }); return { store } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import CustomStore from 'devextreme/data/custom_store'; import { createStore } from 'devextreme-aspnet-data-nojquery'; import TreeList from 'devextreme-react/tree-list'; const serviceUrl = "https://url/to/my/service"; const store = createStore({ key: "ID", loadUrl: serviceUrl + "/GetAction", insertUrl: serviceUrl + "/InsertAction", updateUrl: serviceUrl + "/UpdateAction", deleteUrl: serviceUrl + "/DeleteAction" }); class App extends React.Component { render() { return ( <TreeList ... dataSource={store} /> ); } } export default App;
Any other data source
Implement a CustomStore.
Regardless of the data source on the input, the TreeList always wraps it in the DataSource object. This object allows you to sort, filter, group, and perform other data shaping operations. To get its instance, call the getDataSource() method.
Review the following notes about data binding:
Field names cannot be equal to this
and should not contain the following characters: .
, :
, [
, and ]
.
TreeList does not execute dataSource.sort functions. To implement custom sorting logic, implement columns[].calculateSortValue.
If the TreeList UI component gets data from a server, configure remoteOperations to notify the UI component about data operations the server performs.
Selection works incorrectly with mapped data objects. Use calculated columns instead of mapping.
Notifies the UI component of the used data structure.
The UI component expects that data has a plain structure where:
parentId
and a unique id
;parentId
equal to 0, null or undefined. It indicates that these data items descend from the root node. The root node does not have a visual representation.var treeListData = [ { id: 1, parentId: 0 }, { id: 11, parentId: 1 }, { id: 12, parentId: 1 }, { id: 13, parentId: 1 }, { id: 131, parentId: 13 }, { id: 132, parentId: 13 }, { id: 133, parentId: 13 }, { id: 2, parentId: 0 } ];
Specify the keyExpr and parentIdExpr if parentId
and id
are called differently in your dataset. You can also change the root node's ID from 0 via the rootValue property.
If data has a hierarchical structure, set the dataStructure property to "tree". Parent and item IDs will be generated automatically. Data items that nest other data items should have an items field:
var treeListData = [{ text: "item1", items: [{ text: "item11" }, { text: "item12", items: [ { text: "item121" }, { text: "item122" } ] }] }, { text: "item2" }];
If the items field is called differently in your dataset, specify the itemsExpr property.
If each data item has a Boolean field that specifies whether this data item nests other items, assign the field's name to the hasItemsExpr property. The UI component uses this information to render the expand button. This is required only if the UI component is bound to a remote data source.
Editing does not work with hierarchical data sources out of the box, but you can use the code sample from the following example to implement it:
See AlsoSpecifies the format in which date-time values should be sent to the server.
Specify this property in the following cases:
The dataSource is empty or not set at design time. The dateSerializationFormat is needed, because the TreeList cannot detect it automatically without a data source.
You use the createStore method from the DevExtreme.AspNet.Data extension and remote date-time values are specified in UTC. DevExtreme.AspNet.Data requires the dateSerializationFormat to correctly serialize these values.
Use one of the following values to specify the dateSerializationFormat property:
"yyyy-MM-dd"
- local date
"yyyy-MM-ddTHH:mm:ss"
- local date and time
"yyyy-MM-ddTHH:mm:ssZ"
- UTC date and time
"yyyy-MM-ddTHH:mm:ssx"
, "yyyy-MM-ddTHH:mm:ssxx"
, "yyyy-MM-ddTHH:mm:ssxxx"
- date and time with a timezone
This property applies only if the forceIsoDateParsing field is set to true in the global configuration object.
See AlsoSpecifies whether the UI component responds to user interaction.
Configures editing.
The UI component allows a user to edit data in several modes, which are detailed in the mode property. To define what editing operations a user can perform, specify the allowAdding, allowUpdating and allowDeleting properties. Before enabling an operation, make sure that your data source supports it.
See AlsoSpecifies the global attributes to be attached to the UI component's container element.
Selector: ElementAttr
Default Value: {}
jQuery$(function(){ $("#treeListContainer").dxTreeList({ // ... elementAttr: { id: "elementId", class: "class-name" } }); });Angular
<dx-tree-list ... [elementAttr]="{ id: 'elementId', class: 'class-name' }"> </dx-tree-list>
import { DxTreeListModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })Vue
<template> <DxTreeList ... :element-attr="treeListAttributes"> </DxTreeList> </template> <script> import DxTreeList from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, data() { return { treeListAttributes: { id: 'elementId', class: 'class-name' } } } } </script>React
import React from 'react'; import TreeList from 'devextreme-react/tree-list'; class App extends React.Component { treeListAttributes = { id: 'elementId', class: 'class-name' } render() { return ( <TreeList ... elementAttr={this.treeListAttributes}> </TreeList> ); } } export default App;
Indicates whether to show the error row.
The error row displays data-related errors that may occur on the server during the UI component's runtime. Setting this property to false hides the error row, but the errors can still be viewed in the browser's console.
See AlsoSpecifies expanded rows with keys.
Specifies whether nodes appear expanded or collapsed after filtering is applied.
Configures the integrated filter builder.
Selector: FilterBuilder
Default Value: {}
See the FilterBuilder configuration for properties that you can specify in this object. Do not specify the fields array because the TreeList automatically populates it to sync filter builder fields with grid columns.
AngularThe nested component that configures the filterBuilder property does not support event bindings and two-way property bindings.
VueThe nested component that configures the filterBuilder property does not support event bindings and two-way property bindings.
See AlsoConfigures the popup in which the integrated filter builder is shown.
Selector: FilterBuilderPopup
Default Value: {}
See the Popup configuration for properties that you can specify in this object.
AngularThe nested component that configures the filterBuilderPopup property does not support event bindings and two-way property bindings.
VueThe nested component that configures the filterBuilderPopup property does not support event bindings and two-way property bindings.
See AlsoSpecifies whether filter and search results should include matching rows only, matching rows with ancestors, or matching rows with ancestors and descendants (full branch).
Default Value: 'withAncestors'
Configures the filter panel.
Selector: FilterPanel
Default Value: {}
Configures the filter row.
Specifies whether to synchronize the filter row, header filter, and filter builder. The synchronized filter expression is stored in the filterValue property.
Synchronization is enabled if the filter panel is visible. When it is enabled, check that each column that allows filter operations has the dataField or name property specified.
If this property is enabled, the component keeps filters specified in header filters and filter rows active when columns are hidden.
Specifies a filter expression.
If filterSyncEnabled is true, the filter expression includes a combination of the filter row, header filter, and filter builder filters. Otherwise, it contains only the filter builder filter.
Note that you should convert date strings into JavaScript Date objects before using them in the filter expression.
The filter expression can contain the following operations: "=", "<>", "<", ">", "<=", ">=", "between", "contains", "notcontains", "startswith", "endswith", "anyof", "noneof", and the filter builder's custom operations. Use "anyof" and "noneof" to select and clear the selection of items in the header filter's popup menu. In the following code, "anyof" is used to select items with IDs 500
and 700
:
$(function() { $("#treeListContainer").dxTreeList({ // ... filterSyncEnabled: true, headerFilter: { visible: true }, filterValue: ["ID", "anyof", [500, 700]], }) });Angular
<dx-tree-list ... [filterSyncEnabled]="true" [filterValue]="['ID', 'anyof', [500, 700]]"> <dxo-header-filter [visible]="true"> </dxo-header-filter> </dx-tree-list>
import { DxTreeListModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })Vue
<template> <DxTreeList ... :filter-sync-enabled="true" :filter-value="filterValue"> <DxHeaderFilter :visible="true" /> </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList, { DxHeaderFilter, // ... } from 'devextreme-vue/tree-list'; export default { components: { DxTreeList, DxHeaderFilter, // ... }, data() { return { filterValue: ['ID', 'anyof', [500, 700]] } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList, { HeaderFilter, // ... } from 'devextreme-react/tree-list'; const filterValue = ['ID', 'anyof', [500, 700]]; class App extends React.Component { render() { return ( <TreeList ... filterSyncEnabled={true} defaultFilterValue={filterValue}> <HeaderFilter visible={true} /> </TreeList> ); } } export default App;ASP.NET MVC Controls
@(Html.DevExtreme().DataGrid() // ... .FilterSyncEnabled(true) .HeaderFilter(hf => hf.Visible(true)) .FilterValue("['ID', 'anyof', [500, 700]]") )
If a column's groupInterval property is set, the "anyof" and "noneof" operations for this column accept the beginning of intervals instead of exact values:
jQuery$(function() { $("#treeListContainer").dxTreeList({ // ... headerFilter: { visible: true }, filterValue: ["ID", "anyof", [500, 700]], // Filter intervals are 500-600 and 700-800 columns: [{ dataField: "ID", dataType: "number", headerFilter: { groupInterval: 100 } }, // ... ] }) });Angular
<dx-tree-list ... <!-- Filter intervals are 500-600 and 700-800 --> [(filterValue)]="['ID', 'anyof', [500, 700]]"> <dxo-header-filter [visible]="true"> </dxo-header-filter> <dxi-column dataField="ID" dataType="number"> <dxo-header-filter [groupInterval]="100"> </dxo-header-filter> </dxi-column> </dx-tree-list>
import { DxTreeListModule } from "devextreme-angular"; // ... export class AppComponent { // ... } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })Vue
<template> <DxTreeList ... <!-- Filter intervals are 500-600 and 700-800 --> :filter-value="filterValue"> <DxHeaderFilter :visible="true" /> <DxColumn data-field="ID" data-type="number"> <DxColumnHeaderFilter :group-interval="100" /> </DxColumn> </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList, { DxColumn, DxHeaderFilter, DxColumnHeaderFilter, // ... } from 'devextreme-vue/tree-list'; export default { components: { DxTreeList, DxColumn, DxHeaderFilter, DxColumnHeaderFilter, // ... }, data() { return { filterValue: ['ID', 'anyof', [500, 700]] } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList, { Column, HeaderFilter, ColumnHeaderFilter, // ... } from 'devextreme-react/tree-list'; const filterValue = ['ID', 'anyof', [500, 700]]; class App extends React.Component { render() { return ( <TreeList ... {/* Filter intervals are 500-600 and 700-800 */} defaultFilterValue={filterValue}> <HeaderFilter visible={true} /> <Column dataField="ID" dataType="number"> <ColumnHeaderFilter groupInterval={100} /> </Column> </TreeList> ); } } export default App;ASP.NET MVC Controls
@(Html.DevExtreme().DataGrid() // ... // Filter intervals are 500-600 and 700-800 .HeaderFilter(headerFilter => headerFilter.Visible(true)) .FilterValue("['ID', 'anyof', [500, 700]]") .Columns(columns => { columns.AddFor(m => m.ID) .DataType(GridColumnDataType.Number) .HeaderFilter(hf => hf.GroupInterval(100)); // ... }) )
The
DataSourcedoes not support the
"between",
"anyof",
"noneof", and custom operations. Use the
getCombinedFilter(returnDataField)method to get the
DataSource-compatible filter expression.
See AlsoThe index of the column that contains the focused data cell. This index is taken from the columns array.
Specifies whether the focused row feature is enabled.
The component relies on the key (focusedRowKey) or index (focusedRowIndex) of the focused row to maintain focus. Specify the key to ensure the focused row feature works correctly, as row indexes can change due to filtering or sorting operations. Utilize keyExpr or the key property of the component's store.
The focused row can change if it is hidden by filtering or searching operations. To maintain focus on the same row through filtering and searching operations, set
selection.
modeto "single" instead of enabling
focusedRowEnabled.
The component navigates to the page of the focused row and scrolls to it automatically when you modify focusedRowKey or focusedRowIndex. Assign false
to autoNavigateToFocusedRow to disable this behavior.
TreeList generates requests with comparison operators (such as <
and >
) to calculate the page number of the focused row. This logic does not work for certain key types (such as GUID) and data providers (such as ODataStore). Disable remoteOperations to ensure the component navigates to the focused row correctly.
Specifies or indicates the focused data row's index.
Specifies initially or currently focused grid row's key.
Type: any | undefined
Default Value: undefined
Specifies which data field defines whether the node has children.
If you load data from the server, you need to set this property so that the UI component does not render the expand button for nodes without children.
Configures the header filter feature.
A header filter allows a user to filter values in an individual column by including/excluding them in/from the applied filter. A click on a header filter icon invokes a popup menu with all unique values in the column. By selecting or clearing the selection of values in this menu, the user includes/excludes them in/from the filter.
To make header filter icons visible, assign true to the headerFilter.visible property.
A header filter's popup menu lists all column values. If they are numbers or dates, you can group them using the groupInterval property in the column's headerFilter. You can also provide a custom data source for a header filter using the dataSource property.
If a column has empty cells (null
, undefined
, or ''
), the header filter adds a "(Blanks)" item to its data source. To avoid displaying this "(Blanks)" item, implement DataSource.postProcess in the columns.headerFilter.dataSource method:
$(function() { $("#treeListContainer").dxTreeList({ columns: [{ headerFilter: { dataSource: function (options) { options.dataSource.postProcess = function (results) { return results.filter((item) => item.value !== null) } } } }] }) })Angular
<dx-tree-list ... > <dxo-header-filter [visible]="true"></dxo-header-filter> <dxi-column ... > <dxo-header-filter ... [dataSource]="calculateDataSource" ></dxo-header-filter> </dxi-column> </dx-tree-list>
export class AppComponent { calculateDataSource (options) { options.dataSource.postProcess = function (results) { return results.filter((item) => item.value !== null) } } }Vue
<template> <DxTreeList ... > <DxHeaderFilter :visible="true" /> <DxColumn ... > <DxHeaderFilter ... :data-source="calculateDataSource" /> </DxColumn> </DxTreeList> </template> <script> import DxTreeList, { DxColumn, DxLookup, DxHeaderFilter } from 'devextreme-vue/tree-list'; const calculateDataSource = (options) => { options.dataSource.postProcess = function (results) { return results.filter((item) => item.value !== null) } } </script>React
import TreeList, { Column, Lookup, HeaderFilter } from 'devextreme-react/tree-list'; function calculateDataSource(options) { options.dataSource.postProcess = function (results) { return results.filter((item) => item.value !== null) } } export default function App() { return ( <TreeList ... > <HeaderFilter visible={true} /> <Column ... <HeaderFilter ... dataSource={calculateDataSource} /> </Column> </TreeList> ); }
The user's filtering preferences are saved in the filterValues property. The header filter's Select All checkbox changes the filterType property.
See AlsoSpecifies the UI component's height.
This property accepts a value of one of the following types:
Number
The height in pixels.
String
A CSS-accepted measurement of height. For example, "55px"
, "20vh"
, "80%"
, "inherit"
.
Specifies whether to highlight rows and cells with edited data. repaintChangesOnly should be true.
Collaborative Editing Demo SignalR Service Demo
You can change the following CSS rules and classes that control highlighting:
@keyframes dx-treelist-highlight-change { from { background-color: #efefef; } 50% { background-color: #efefef; } } .dx-treelist-cell-updated-animation { animation: dx-treelist-highlight-change 1s; } .dx-treelist-row-inserted-animation { animation: dx-treelist-highlight-change 1s; }
Specifies text for a hint that appears when a user pauses on the UI component.
Specifies whether to highlight rows when a user moves the mouse pointer over them.
Specifies which data field contains nested items. Set this property when your data has a hierarchical structure.
Configures keyboard navigation.
Selector: KeyboardNavigation
Specifies the key property (or properties) that provide(s) key values to access data items. Each key value must be unique.
Configures the load panel.
The load panel is displayed while the UI component loads data. It consists of a loading indicator and text, both placed on a pane.
Since the load panel is, in fact, the DevExtreme LoadPanel UI component, the loadPanel object can contain any properties of this UI component along with properties described here.
See AlsoSpecifies a text string shown when the TreeList does not display any data.
A function that is executed before an adaptive detail row is rendered.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
Adaptive detail rows display information from columns that were hidden when the UI component adapted to the screen or container size. Each adaptive detail row contains the Form UI component that you can customize within the onAdaptiveDetailRowPreparing function using the formOptions object. Refer to the Form Configuration section for details on properties of the Form UI component.
jQuery$(function() { $("#treeListContainer").dxTreeList({ // ... onAdaptiveDetailRowPreparing: function(e) { e.formOptions.colCount = 2; e.formOptions.colCountByScreen = { xs: 2 } e.formOptions.labelLocation = 'left'; } }) })Angular
import { DxTreeListModule } from "devextreme-angular"; // ... export class AppComponent { onAdaptiveDetailRowPreparing(e) { e.formOptions.colCount = 2; e.formOptions.colCountByScreen = { xs: 2 } e.formOptions.labelLocation = 'left'; } } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })
<dx-tree-list ... (onAdaptiveDetailRowPreparing)="onAdaptiveDetailRowPreparing($event)"> </dx-tree-list>Vue
App.vue (Composition API)
<template> <DxTreeList @adaptive-detail-row-preparing="onAdaptiveDetailRowPreparing" /> </template> <script> import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, methods: { onAdaptiveDetailRowPreparing(e) { e.formOptions.colCount = 2; e.formOptions.colCountByScreen = { xs: 2 } e.formOptions.labelLocation = 'left'; } } } </script>
<template> <DxTreeList @adaptive-detail-row-preparing="onAdaptiveDetailRowPreparing" /> </template> <script setup> import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-vue/tree-list'; const onAdaptiveDetailRowPreparing = (e) => { e.formOptions.colCount = 2; e.formOptions.colCountByScreen = { xs: 2 } e.formOptions.labelLocation = 'left'; } </script>React
import { useCallback } from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-react/tree-list'; export default function App() { const onAdaptiveDetailRowPreparing = useCallback((e) => { e.formOptions.colCount = 2; e.formOptions.colCountByScreen = { xs: 2 } e.formOptions.labelLocation = 'left'; }, []); return ( <TreeList onAdaptiveDetailRowPreparing={onAdaptiveDetailRowPreparing} /> ); }See Also
A function that is executed when a cell is clicked or tapped. Executed before onRowClick.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description cellElementThe cell's container. It is an HTML Element or a jQuery Element when you use jQuery.
columnThis column's configuration.
columnIndexThe index of the column to which the cell belongs.
componentThe UI component's instance.
dataThe data of the row to which the cell belongs. Available if the rowType is "data", "detail" or "detailAdaptive".
displayValue anyThe cell's displayed value. Available if the rowType is "data".
Differs from the value field only when the cell belongs to the lookup column.
The UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
eventEvent (jQuery or EventObject)
The event that caused the function to execute. It is an EventObject or a jQuery.Event when you use jQuery.
key anyThe row's key. Available if the rowType is "data", "detail" or "detailAdaptive".
For plain data, the key value depends on the keyExpr property. For hierarchical data, the key is generated automatically or set in the underlying Store of the data source.
The row properties. Available if the rowType is "data", "detail" or "detailAdaptive".
rowIndexThe index of the row to which the cell belongs. Refer to Column and Row Indexes for more information.
rowTypeThe row's type.
textThe cell's formatted value converted to a string. Available if the rowType is "data".
value anyThe cell's raw value. Available if the rowType is "data".
Default Value: null
A function that is executed when a cell is double-clicked or double-tapped. Executed before onRowDblClick.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description cellElementThe cell's container. It is an HTML Element or a jQuery Element when you use jQuery.
columnThe column's configuration.
columnIndexThe index of the column the cell belongs to.
componentThe UI component's instance.
dataThe data of the row the cell belongs to. Available if the rowType is "data", "detail" or "detailAdaptive".
displayValue anyThe value displayed in the cell. Available if the rowType is "data".
Differs from the value field only when the cell belongs to a lookup column.
The UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
eventEvent (jQuery or EventObject)
The event that caused the function to execute. It is an EventObject or a jQuery.Event when you use jQuery.
key anyThe row's key. Available if the rowType is "data", "detail" or "detailAdaptive".
rowThe row's properties. Available if the rowType is "data", "detail" or "detailAdaptive".
rowIndexThe index of the row the cell belongs to. Refer to Column and Row Indexes for more information.
rowTypeThe row's type.
textThe cell's formatted value converted to a string. Available if the rowType is "data".
value anyThe cell's raw value. Available if the rowType is "data".
Default Value: null
A function that is executed after the pointer enters or leaves a cell.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description cellElementThe cell's container. It is an HTML Element or a jQuery Element when you use jQuery.
columnThis column's configuration.
columnIndexThe index of the column to which the cell belongs.
componentThe UI component's instance.
dataThe data of the row to which the cell belongs. Available if the rowType is "data", "detail" or "detailAdaptive".
displayValue anyThe cell's displayed value. Available if the rowType is "data".
Differs from the value field only when the cell belongs to the lookup column.
The UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
eventTypeIndicates whether the pointer entered or left the cell. Can be either "mouseover" or "mouseout".
key anyThe row's key. Available if the rowType is "data", "detail" or "detailAdaptive".
For plain data, the key value depends on the keyExpr property. For hierarchical data, the key is generated automatically or set in the underlying Store of the data source.
The row properties. Available if the rowType is "data", "detail" or "detailAdaptive".
rowIndexThe index of the row to which the cell belongs. Refer to Column and Row Indexes for more information.
rowTypeThe row's type.
textThe cell's formatted value converted to a string. Available if the rowType is "data".
value anyThe cell's raw value. Available if the rowType is "data".
Default Value: null
To identify whether the pointer has entered or left the cell, check the eventType field's value.
A function that is executed after a grid cell is created.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description cellElementThe cell's container. It is an HTML Element or a jQuery Element when you use jQuery.
columnThis column's configuration.
columnIndexThe visible column index described in the following topic: Column and Row Indexes.
componentThe UI component's instance.
dataThe data of the row to which the cell belongs. Available if the rowType is "data", "detail", or "detailAdaptive".
displayValue anyThe cell's displayed value. Available if the rowType is "data".
Differs from the value field only when the column to which the prepared cell belongs uses lookup.
The UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
isExpandedIndicates whether the row is expanded or collapsed. Available if rowType is "data".
isNewRowIndicates that the row is added, but not yet saved. Available if rowType is "data".
isSelectedIndicates whether the row is selected. Available if rowType is "data" or "detail".
key anyThe row's key. Available if the rowType is "data", "detail" or "detailAdaptive".
For plain data, the key value depends on the keyExpr property. For hierarchical data, the key is generated automatically or set in the underlying Store of the data source.
The cell's previous raw value. Defined only if repaintChangesOnly is true.
rowRow properties.
rowIndexThe row's index. Refer to Column and Row Indexes for more information.
rowTypeThe row's type.
textThe cell's formatted value converted to a string. Available if the rowType is "data".
value anyThe cell's raw value. Available if the rowType is "data".
watchAllows you to track a variable and execute actions when it changes. Applies when repaintChangesOnly is true.
This function has the following parameters:
getter(data): Function
A function that returns the variable that should be tracked.
handler(newValue): Function
A function called when this variable changes.
Default Value: null
In the following code, the onCellPrepared function is used to change a ProductName
's color depending on the Amount
of sold products. You can paste this code in the Real-Time Updates demo and see how it works.
$(function() { $("#treeListContainer").dxTreeList({ // ... repaintChangesOnly: true, onCellPrepared: function(e) { if(e.rowType === "data" && e.column.dataField === "ProductName") { e.cellElement.css("color", e.data.Amount >= 10000 ? "green" : "red"); // Tracks the `Amount` data field e.watch(function() { return e.data.Amount; }, function() { e.cellElement.css("color", e.data.Amount >= 10000 ? "green" : "red"); }) } } }) })Angular
import { DxTreeListModule } from "devextreme-angular"; // ... export class AppComponent { onCellPrepared(e) { if(e.rowType === "data" && e.column.dataField === "ProductName") { e.cellElement.style.color = e.data.Amount >= 10000 ? "green" : "red"; // Tracks the `Amount` data field e.watch(function() { return e.data.Amount; }, function() { e.cellElement.style.color = e.data.Amount >= 10000 ? "green" : "red"; }) } } } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })
<dx-tree-list ... [repaintChangesOnly]="true" (onCellPrepared)="onCellPrepared($event)"> </dx-tree-list>Vue
<template> <DxTreeList :repaint-changes-only="true" @cell-prepared="onCellPrepared" /> </template> <script> import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, methods: { onCellPrepared(e) { if(e.rowType === "data" && e.column.dataField === "ProductName") { e.cellElement.style.color = e.data.Amount >= 10000 ? "green" : "red"; // Tracks the `Amount` data field e.watch(function() { return e.data.Amount; }, function() { e.cellElement.style.color = e.data.Amount >= 10000 ? "green" : "red"; }) } } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-react/tree-list'; class App extends React.Component { // ... render() { return ( <TreeList repaintChangesOnly={true} onCellPrepared={this.onCellPrepared} /> ); } onCellPrepared = (e) => { if(e.rowType === "data" && e.column.dataField === "ProductName") { e.cellElement.style.color = e.data.Amount >= 10000 ? "green" : "red"; // Tracks the `Amount` data field e.watch(function() { return e.data.Amount; }, function() { e.cellElement.style.color = e.data.Amount >= 10000 ? "green" : "red"; }) } } } export default App;ASP.NET MVC Controls
@(Html.DevExtreme().TreeList() .ID("treeListContainer") // ... .RepaintChangesOnly(true) .OnCellPrepared("treeList_cellPrepared_handler") ) <script> function treeList_cellPrepared_handler(e) { if (e.rowType === "data" && e.column.dataField === "ProductName") { e.cellElement.css("color", e.data.Amount >= 10000 ? "green" : "red"); // Tracks the `Amount` data field e.watch(function() { return e.data.Amount; }, function() { e.cellElement.css("color", e.data.Amount >= 10000 ? "green" : "red"); }) } } </script>
To learn how to use onCellPrepared to display a tooltip for data cells, refer to the following example:
To learn how to implement conditional formatting with onCellPrepared, refer to the following example:
See AlsoA function that is executed when the UI component is rendered and each time the component is repainted.
Function parameters:Information about the event.
Object structure:
Default Value: null
A function that is executed before the context menu is rendered.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
In the following code, the onContextMenuPreparing function adds a custom item to the context menu invoked when a user right-clicks any column header:
jQuery$(function() { $("#treeListContainer").dxTreeList({ // ... onContextMenuPreparing: function(e) { if (e.target == "header") { // e.items can be undefined if (!e.items) e.items = []; // Add a custom menu item e.items.push({ text: "Log Column Caption", onItemClick: function() { console.log(e.column.caption); } }); } } }); });Angular
<dx-tree-list ... (onContextMenuPreparing)="addMenuItems($event)"> </dx-tree-list>
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { addMenuItems(e) { if (e.target == 'header') { // e.items can be undefined if (!e.items) e.items = []; // Add a custom menu item e.items.push({ text: 'Log Column Caption', onItemClick: () => { console.log(e.column.caption); } }); } } }
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { DxTreeListModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, DxTreeListModule ], providers: [ ], bootstrap: [AppComponent] }) export class AppModule { }Vue
<template> <DxTreeList ... @context-menu-preparing="addMenuItems"> </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, data() { return { // ... } }, methods: { addMenuItems(e) { if (e.target == 'header') { // e.items can be undefined if (!e.items) e.items = []; // Add a custom menu item e.items.push({ text: 'Log Column Caption', onItemClick: () => { console.log(e.column.caption); } }); } } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-react/tree-list'; class App extends React.Component { addMenuItems(e) { if (e.target == 'header') { // e.items can be undefined if (!e.items) e.items = []; // Add a custom menu item e.items.push({ text: 'Log Column Caption', onItemClick: () => { console.log(e.column.caption); } }); } } render() { return ( <TreeList ... onContextMenuPreparing={this.addMenuItems}> </TreeList> ); } } export default App;
A function that is executed when an error occurs in the data source.
Function parameters:Information on the occurred error.
Object structure:
Default Value: null
Handles errors that might occur in the data source. To obtain a human-readable description of the error in the function, use the error.message field.
A function that is executed before the UI component is disposed of.
Function parameters:Information about the event.
Object structure:
Default Value: null
A function that is executed after row changes are discarded.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
A function that is executed when the edit operation is canceled, but row changes are not yet discarded.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description changesArray<DataChange>
Row changes to be discarded.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
cancelSet this field to true if the row changes should not be discarded.
Default Value: null
An edit operation can be canceled from the UI (with the Cancel button) or programatically (with the cancelEditData() method).
A function that is executed before a cell or row switches to the editing state.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description cancelAllows you to cancel row editing.
columnThe configuration of the column whose cell is switching to the editing state. Available in "cell" and "batch" editing modes.
componentThe UI component's instance.
dataThe data of the row to be edited.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
key anyThe row's key.
The key of an added but not yet saved row is undefined.
Default Value: null
If the editing.mode is "batch" or "cell", this function is executed while the UI component renders columns of boolean
dataType and other columns whose showEditorAlways property is true.
A function that is executed after an editor is created. Not executed for cells with an editCellTemplate.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description componentThe UI component's instance.
dataFieldThe name of the field that provides data for the column the editor belongs to.
disabledIndicates whether the editor is disabled.
editorElementThe editor's container. It is an HTML Element or a jQuery Element when you use jQuery.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
parentTypeThe editor's location. One of "dataRow", "filterRow", "headerRow" or "searchPanel".
readOnlyIndicates whether the editor is read-only.
rowThe properties of the row the editor belongs to.
rtlEnabledIndicates whether the editor uses right-to-left representation.
setValue anyA method you should call to change the cell value and, optionally, the displayed value after the editor's value is changed.
updateValueTimeoutGets and sets the delay between the moment a user stops typing a filter value and the change is applied. Available if the parentType is "filterRow" or "searchPanel".
value anyThe editor's value.
widthThe editor's width; equals null for all editors except for those whose parentType equals "searchPanel".
Default Value: null
A function used to customize cell editors. Not executed for cells with an editCellTemplate.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description cancelAllows you to cancel editor creation.
You can set this field's value to true and implement a custom editor.
The UI component's instance.
dataFieldThe name of the field that provides data for the column the editor belongs to.
disabledIndicates whether the editor is disabled.
editorElementThe editor's container. It is an HTML Element or a jQuery Element when you use jQuery.
editorNameAllows you to change the editor. Accepts names of DevExtreme UI components only, for example, "dxTextBox".
Import a new editor's module when DevExtreme modules are used.
Gets and sets editor configuration.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
parentTypeThe editor's location. One of "dataRow", "filterRow", "headerRow" or "searchPanel".
readOnlyIndicates whether the editor is read-only.
rowThe properties of the row the editor belongs to.
rtlEnabledIndicates whether the editor uses right-to-left representation.
setValue anyUse this method to change the cell/editor value. You can also pass a second parameter to change cell values in columns with calculateDisplayValue specified.
updateValueTimeoutGets and sets the delay between the moment a user stops typing a filter value and the change is applied. Available if the parentType is "filterRow" or "searchPanel".
value anyEditor value. This field is read-only. To change the editor value, use the setValue(newValue) function parameter.
widthThe editor's width; equals null for all editors except for those whose parentType equals "searchPanel".
Default Value: null
Use this function to:
Override the default editor's onValueChanged handler. For other default editor customizations, use editorOptions.
jQuery$(function() { $("#treeListContainer").dxTreeList({ // ... onEditorPreparing: function(e) { if (e.dataField === "requiredDataField" && e.parentType === "dataRow") { const defaultValueChangeHandler = e.editorOptions.onValueChanged; e.editorOptions.onValueChanged = function(args) { // Override the default handler // ... // Custom commands go here // ... // If you want to modify the editor value, call the setValue function: // e.setValue(newValue); // Otherwise, call the default handler: defaultValueChangeHandler(args); } } } }); });Angular
<dx-tree-list ... (onEditorPreparing)="overrideOnValueChanged($event)"> </dx-tree-list>
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { overrideOnValueChanged(e) { if (e.dataField === 'requiredDataField' && e.parentType === 'dataRow') { const defaultValueChangeHandler = e.editorOptions.onValueChanged; e.editorOptions.onValueChanged = function (args) { // Override the default handler // ... // Custom commands go here // ... // If you want to modify the editor value, call the setValue function: // e.setValue(newValue); // Otherwise, call the default handler: defaultValueChangeHandler(args); } } } }
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { DxTreeListModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, DxTreeListModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }Vue
<template> <DxTreeList ... @editor-preparing="overrideOnValueChanged"> </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, // ... methods: { overrideOnValueChanged(e) { if (e.dataField === 'requiredDataField' && e.parentType === 'dataRow') { const defaultValueChangeHandler = e.editorOptions.onValueChanged; e.editorOptions.onValueChanged = function (args) { // Override the default handler // ... // Custom commands go here // ... // If you want to modify the editor value, call the setValue function: // e.setValue(newValue); // Otherwise, call the default handler: defaultValueChangeHandler(args); } } } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-react/tree-list'; class App extends React.Component { overrideOnValueChanged(e) { if (e.dataField === 'requiredDataField' && e.parentType === 'dataRow') { const defaultValueChangeHandler = e.editorOptions.onValueChanged; e.editorOptions.onValueChanged = function (args) { // Override the default handler // ... // Custom commands go here // ... // If you want to modify the editor value, call the setValue function: // e.setValue(newValue); // Otherwise, call the default handler: defaultValueChangeHandler(args); } } } render() { return ( <TreeList ... onEditorPreparing={this.overrideOnValueChanged}> </TreeList> ); } } export default App;ASP.NET MVC Controls
@(Html.DevExtreme().TreeList() // ... .OnEditorPreparing("overrideOnValueChanged") ) <script type="text/javascript"> function overrideOnValueChanged(e) { if (e.dataField === "requiredDataField" && e.parentType === "dataRow") { const defaultValueChangeHandler = e.editorOptions.onValueChanged; e.editorOptions.onValueChanged = function(args) { // Override the default handler // ... // Custom commands go here // ... // If you want to modify the editor value, call the setValue function: // e.setValue(newValue); // Otherwise, call the default handler: defaultValueChangeHandler(args); } } } </script>
Customize editors used in the search panel, filter row, and selection column.
Use the parentType function parameter to check if the editor that the function customizes belongs to one of these UI elements.
Implement other customization cases.
We do not recommend setting default editor values in onEditorPreparing. Implement onInitNewRow and onEditingStart to specify default editor values.
This function has higher priority over other editing tools. The order of priority is as follows: onEditorPreparing > columns.formItem > editing.form.
A function that is executed after the focused cell changes. Applies only to cells in data rows.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
A function that is executed before the focused cell changes. Applies only to cells in data rows.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description cancelAllows you to cancel focusing a new cell.
cellElementThe to-be-focused cell's container. It is an HTML Element or a jQuery Element when you use jQuery.
columnsThe visible columns' properties.
componentThe UI component's instance.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
eventEvent (jQuery or EventObject)
The event that caused the function to execute. It is an EventObject or a jQuery.Event when you use jQuery.
isHighlightedtrue if the cell is highlighted; otherwise false, even if the cell's row is highlighted.
newColumnIndexThe index of the column the cell that should be focused belongs to.
newRowIndexThe index of the row the cell that should be focused belongs to.
prevColumnIndexThe index of the previously focused cell's column.
prevRowIndexThe index of the previously focused cell's row.
rowsThe visible rows' properties.
Default Value: null
In the following code, the onFocusedCellChanging function is used to customize keyboard navigation within a row. The cell navigation is looped in a single row because focus moves to the row's first cell after reaching the last cell and vice versa:
jQuery$(function() { $("#treeListContainer").dxTreeList({ // ... onFocusedCellChanging: function (e) { if (e.newColumnIndex == e.prevColumnIndex) { e.newColumnIndex = (e.newColumnIndex == 0 ? e.columns.length - 1 : 0) } } }); });Angular
import { DxTreeListModule } from "devextreme-angular"; // ... export class AppComponent { onFocusedCellChanging (e) { if (e.newColumnIndex == e.prevColumnIndex) { e.newColumnIndex = (e.newColumnIndex == 0 ? e.columns.length - 1 : 0) } } } @NgModule({ imports: [ // ... DxTreeListModule ], // ... })
<dx-tree-list ... (onFocusedCellChanging)="onFocusedCellChanging($event)"> </dx-tree-list>Vue
<template> <DxTreeList ... @focused-cell-changing="onFocusedCellChanging" > </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import { DxTreeList } from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, methods: { onFocusedCellChanging(e) { if (e.newColumnIndex == e.prevColumnIndex) { e.newColumnIndex = (e.newColumnIndex == 0 ? e.columns.length - 1 : 0); } } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-react/tree-list'; class App extends React.Component { render() { return ( <TreeList ... onFocusedCellChanging={this.onFocusedCellChanging} > </TreeList> ); } onFocusedCellChanging(e) { if (e.newColumnIndex == e.prevColumnIndex) { e.newColumnIndex = (e.newColumnIndex == 0 ? e.columns.length - 1 : 0); } } } export default App;See Also
A function that executed when the focused row changes. Applies only to data rows. focusedRowEnabled should be true.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
A function that is executed before the focused row changes. Applies only to data rows. focusedRowEnabled should be true.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
A function used in JavaScript frameworks to save the UI component instance.
Function parameters:Information about the event.
Object structure:
Default Value: null
Angular<dx-tree-list ... (onInitialized)="saveInstance($event)"> </dx-tree-list>
import { Component } from "@angular/core"; import TreeList from "devextreme/ui/data_grid"; // ... export class AppComponent { treeListInstance: TreeList; saveInstance (e) { this.treeListInstance = e.component; } }Vue
App.vue (Composition API)
<template> <div> <DxTreeList ... @initialized="saveInstance"> </DxTreeList> </div> </template> <script> import DxTreeList from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, data: function() { return { treeListInstance: null }; }, methods: { saveInstance: function(e) { this.treeListInstance = e.component; } } }; </script>
<template> <div> <DxTreeList ... @initialized="saveInstance"> </DxTreeList> </div> </template> <script setup> import DxTreeList from 'devextreme-vue/tree-list'; let treeListInstance = null; const saveInstance = (e) => { treeListInstance = e.component; } </script>React
import TreeList from 'devextreme-react/tree-list'; class App extends React.Component { constructor(props) { super(props); this.saveInstance = this.saveInstance.bind(this); } saveInstance(e) { this.treeListInstance = e.component; } render() { return ( <div> <TreeList onInitialized={this.saveInstance} /> </div> ); } }See Also jQuery
A function that is executed before a new row is added to the UI component.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description promisePromise<void> (jQuery or native)
Assign a Promise to this field to perform an asynchronous operation, such as a request to a server.
dataThe data of the inserted row; initially empty.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
You can use this function to populate a new row with data. Add fields to the data object that correspond to the data source object's fields. Note that the data object can omit some fields from the data source object. Add only those fields that should initialize specific cells of a new row.
In the following code, the onInitNewRow function is used to provide default values for the new row's ID
, hireDate
, and position
cells. The promise parameter is used to obtain values for the ID
and position
cell values asynchronously:
$(function() { $("#treeListContainer").dxTreeList({ dataSource: [{ ID: 1, hireDate: 1491821760000, position: "CTO" }, // ... ], columns: [ "ID", { dataField: "hireDate", dataType: "date" }, "position" ], onInitNewRow: function(e) { e.data.hireDate = new Date(); e.promise = getDefaultData().done(function(data) { e.data.ID = data.ID; e.data.position = data.Position; }); } }); function getDefaultData() { var promise = $.ajax({ // The URL returns { ID: 100, Position: "Programmer" } url: "https://www.mywebsite.com/api/getDefaultData", dataType: "json" }); return promise; } })Angular
<dx-tree-list ... [dataSource]="employees" (onInitNewRow)="onInitNewRow($event)"> <dxi-column dataField="ID"></dxi-column> <dxi-column dataField="hireDate" dataType="date"></dxi-column> <dxi-column dataField="position"></dxi-column> </dx-tree-list>
import { Component } from '@angular/core'; import { lastValueFrom } from 'rxjs'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { employees = [{ ID: 1, hireDate: 1491821760000, position: "CTO" }, // ... ]; onInitNewRow(e) { e.data.hireDate = new Date(); e.promise = this.getDefaultData().then((data: any) => { e.data.ID = data.ID; e.data.position = data.Position; }); } async getDefaultData() { try { const data = await lastValueFrom(this.httpClient.get("https://www.mywebsite.com/api/getDefaultData")); // "data" is { ID: 100, Position: "Programmer" } return data; } catch (error) { throw 'Data Loading Error'; } } }
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { DxTreeListModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, DxTreeListModule ], providers: [ ], bootstrap: [AppComponent] }) export class AppModule { }Vue
<template> <DxTreeList ... :data-source="employees" @init-new-row="initNewRow"> <DxColumn data-field="ID" /> <DxColumn data-field="hireDate" data-type="date" /> <DxColumn data-field="position" /> </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import { DxTreeList, DxColumn } from 'devextreme-vue/tree-list'; import 'whatwg-fetch'; const employees = [{ ID: 1, hireDate: 1491821760000, position: "CTO" }, // ... ]; export default { components: { DxTreeList, DxColumn }, data() { employees }, methods: { initNewRow(e) { e.data.hireDate = new Date(); e.promise = this.getDefaultData().then(data => { e.data.ID = data.ID; e.data.position = data.Position; }); } getDefaultData() { return fetch("https://www.mywebsite.com/api/getDefaultData") .then(response => response.json()) .then((data) => { // "data" is { ID: 100, Position: "Programmer" } return data; }) .catch(() => { throw 'Data Loading Error' }); } } }; </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import { TreeList, Column } from 'devextreme-react/tree-list'; import 'whatwg-fetch'; const employees = [{ ID: 1, hireDate: 1491821760000, position: "CTO" }, // ... ]; class App extends React.Component { constructor(props) { super(props); this.onInitNewRow = this.onInitNewRow.bind(this); this.getDefaultData = this.getDefaultData.bind(this); } onInitNewRow(e) { e.promise = this.getDefaultData().then(data => { e.data.ID = data.ID; e.data.position = data.Position; }); e.data.hireDate = new Date(); } getDefaultData() { return fetch("https://www.mywebsite.com/api/getDefaultData") .then(response => response.json()) .then((data) => { // "data" is { ID: 100, Position: "Programmer" } return data; }) .catch(() => { throw 'Data Loading Error' }); } render() { return ( <TreeList ... dataSource={employees} onInitNewRow={this.onInitNewRow}> <Column dataField="ID" /> <Column dataField="hireDate" dataType="date" /> <Column dataField="position" /> </TreeList> ); } } export default App;ASP.NET MVC Controls
@(Html.DevExtreme().TreeList() .DataSource(new JS("employees")) .Columns(c => { c.Add().DataField("ID"); c.Add().DataField("hireDate") .DataType(GridColumnDataType.Date); c.Add().DataField("position"); }) .OnInitNewRow("onInitNewRow") ) <script type="text/javascript"> var employees = [{ ID: 1, hireDate: 1491821760000, position: "CTO" }, // ... ]; function onInitNewRow(e) { e.data.hireDate = new Date(); e.promise = getDefaultData().done(data => { e.data.ID = data.ID; e.data.position = data.Position; }); } function getDefaultData() { let promise = $.ajax({ // The URL returns { ID: 100, Position: "Programmer" } url: "https://www.mywebsite.com/api/getDefaultData", dataType: "json", }); return promise; } </script>
A function that is executed when the UI component is in focus and a key has been pressed down.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
The following code shows how to handle a key combination:
jQuery$(function() { $("#treeList").dxTreeList({ // ... onKeyDown(e) { if (e.event.ctrlKey && e.event.key === "Q") { console.log("Ctrl + Q was pressed"); } } }); });Angular
<dx-tree-list ... (onKeyDown)="onKeyDown($event)"> </dx-tree-list>
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { onKeyDown(e) { if (e.event.ctrlKey && e.event.key === "Q") { console.log("Ctrl + Q was pressed"); } } }
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { DxTreeListModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, DxTreeListModule ], providers: [ ], bootstrap: [AppComponent] }) export class AppModule { }Vue
<template> <DxTreeList ... @key-down="onKeyDown"> </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, methods: { onKeyDown(e) { if (e.event.ctrlKey && e.event.key === "Q") { console.log("Ctrl + Q was pressed"); } } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-react/tree-list'; class App extends React.Component { render() { return ( <TreeList ... onKeyDown={this.onKeyDown}> </TreeList> ); } onKeyDown(e) { if (e.event.ctrlKey && e.event.key === "Q") { console.log("Ctrl + Q was pressed"); } } } export default App;
A function that is executed after the loaded nodes are initialized.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
Use this function to modify node fields. You can traverse the tree using the forEachNode(callback) method or implement your custom algorithm. In a custom algorithm, access the root node first - use the function parameter's root field. Use the the children field to access first-level child nodes. Do the same for every node in the collection. Thus you can traverse the entire tree.
A function that is executed after a UI component property is changed.
Function parameters:Information about the event.
Object structure:
Name Type Description value anyThe modified property's new value.
previousValue anyThe UI component's previous value.
nameThe modified property if it belongs to the first level. Otherwise, the first-level property it is nested into.
fullNameThe path to the modified property that includes all parent properties.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
The following example shows how to subscribe to component property changes:
jQuery$(function() { $("#treeListContainer").dxTreeList({ // ... onOptionChanged: function(e) { if(e.name === "changedProperty") { // handle the property change here } } }); });Angular
<dx-tree-list ... (onOptionChanged)="handlePropertyChange($event)"> </dx-tree-list>
import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { // ... handlePropertyChange(e) { if(e.name === "changedProperty") { // handle the property change here } } }
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { DxTreeListModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, DxTreeListModule ], providers: [ ], bootstrap: [AppComponent] }) export class AppModule { }Vue
<template> <DxTreeList ... @option-changed="handlePropertyChange" /> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList from 'devextreme-vue/tree-list'; export default { components: { DxTreeList }, // ... methods: { handlePropertyChange: function(e) { if(e.name === "changedProperty") { // handle the property change here } } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-react/tree-list'; const handlePropertyChange = (e) => { if(e.name === "changedProperty") { // handle the property change here } } export default function App() { return ( <TreeList ... onOptionChanged={handlePropertyChange} /> ); }
A function that is executed when a grid row is clicked or tapped.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
Prior to this function, the UI component executes the onCellClick function and sometimes internal functions. You can use the handled field to check whether internal functions were executed.
When the clicked row is in the editing state or switches to this state, the onRowClick function is not executed. Instead, specify the onCellClick function.
A function that is executed after a row is collapsed.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
A function that is executed before a row is collapsed.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
To cancel row collapsing, assign true to the cancel field of the function parameter.
A function that is executed when a row is double-clicked or double-tapped. Executed after onCellDblClick.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
onRowDblClick is not executed when the clicked row is in the editing state or switches to this state. You can use onCellDblClick instead.
A function that is executed after a row is expanded.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
A function that is executed before a row is expanded.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
To cancel row expansion, assign true to the cancel field of the function parameter.
A function that is executed after a new row has been inserted into the data source.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description key anyThe key of the row. If a field providing keys is not specified in the data source, the whole data object is considered the key.
errorThe standard Error object defining an error that may occur during insertion.
dataThe data of the row.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
In batch
editing mode, if several rows have been inserted, this function will be executed for each row individually.
A function that is executed before a new row is inserted into the data source.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description dataThe data of the row that should be inserted.
cancel |Promise<Boolean> (jQuery or native)
|Promise<void> (jQuery or native)
true, a Promise resolved with true, or a rejected Promise stops row insertion.
false or a Promise resolved with false or undefined continues row insertion.
The UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
This function allows you to intercept row insertion and perform additional actions. The following code shows how to use the function parameter's cancel field to prevent or continue row insertion. In this code, a Promise is assigned to this field. Row insertion continues if a user confirms it and row data validation on the server succeeds (the Promise is resolved); otherwise, row insertion is prevented (the Promise is rejected):
jQuery$(function(){ $("#treeListContainer").dxTreeList({ // ... onRowInserting: function(e) { const deferred = $.Deferred(); const promptPromise = DevExpress.ui.dialog.confirm("Are you sure?", "Confirm changes"); promptPromise.done((dialogResult) => { if (dialogResult) { $.ajax({ url: "https://url/to/your/validation/service", dataType: "json", data: e.newData, success: function(validationResult) { if (validationResult.errorText) { deferred.reject(validationResult.errorText); } else { deferred.resolve(false); } }, error: function() { deferred.reject("Data Loading Error"); }, timeout: 5000 }); } else { deferred.resolve(true); } }); e.cancel = deferred.promise(); } }) })Angular
import { HttpClient, HttpClientModule, HttpParams } from "@angular/common/http"; import { confirm } from 'devextreme/ui/dialog'; import { lastValueFrom } from 'rxjs'; // ... export class AppComponent { constructor(private httpClient: HttpClient) { /*...*/ } async insertRow(e) { try { const dialogResult = await this.confirmAsync("Are you sure?", "Confirm changes"); if (dialogResult) { let params = new HttpParams(); for (let key in e.newData) { params = params.set(key, e.newData[key]); } const validationResult = await lastValueFrom(this.httpClient.get("https://url/to/your/validation/service", { params })); if (validationResult.errorText) { throw validationResult.errorText; } else { e.cancel = false; } } else { e.cancel = true; } } catch (error) { console.error("Validation or confirmation error", error); e.cancel = Promise.reject(error); } } private confirmAsync(message: string, title?: string): Promise<boolean> { return new Promise<boolean>((resolve) => { const dialogResult = confirm(message, title); resolve(dialogResult); }); } }
<dx-tree-list ... (onRowInserting)="insertRow($event)"> </dx-tree-list>
// ... import { DxTreeListModule } from 'devextreme-angular'; import { HttpClientModule } from "@angular/common/http"; @NgModule({ imports: [ // ... DxTreeListModule, HttpClientModule ], // ... })Vue
<template> <DxTreeList ... @row-inserting="insertRow"> </DxTreeList> </template> <script> import DxTreeList, { ... } from 'devextreme-vue/tree-list'; import { confirm } from 'devextreme/ui/dialog'; // ... export default { components: { DxTreeList, // ... }, // ... methods: { insertRow(e) { const isCanceled = new Promise((resolve, reject) => { const promptPromise = confirm("Are you sure?", "Confirm changes"); promptPromise.then((dialogResult) => { if (dialogResult) { let params = new HttpParams(); for (let key in e.newData) { params = params.set(key, e.newData[key]); } fetch(`https://url/to/your/validation/service${params}`) .then((validationResult) => { if (validationResult.errorText) { reject(validationResult.errorText); } else { resolve(false); } }); } else { return resolve(true); } }); }); e.cancel = isCanceled; } }, }; </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import { confirm } from 'devextreme/ui/dialog'; import TreeList, { ... } from 'devextreme-react/tree-list'; function insertRow(e) { const isCanceled = new Promise((resolve, reject) => { const promptPromise = confirm("Are you sure?", "Confirm changes"); promptPromise.then((dialogResult) => { if (dialogResult) { let params = new HttpParams(); for (let key in e.newData) { params = params.set(key, e.newData[key]); } fetch(`https://url/to/your/validation/service${params}`) .then((validationResult) => { if (validationResult.errorText) { reject(validationResult.errorText); } else { resolve(false); } }); } else { return resolve(true); } }); }); e.cancel = isCanceled; } function App() { return ( <TreeList ... onRowInserting={insertRow}> // ... </TreeList> ); } export default App;
Do not use this function to insert data. If you need a custom insert logic, implement CustomStore's insert function.
In batch editing mode, this function is executed for each row individually if several rows should be inserted.
A function that is executed after a row is created.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description columnsAll column configurations.
componentThe UI component's instance.
dataThe row's data. Available if the rowType is "data", "detail" or "detailAdaptive".
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
isExpandedIndicates whether the row is expanded or collapsed. Available if rowType is "data".
isNewRowIndicates that the row is added, but not yet saved. Available if rowType is "data".
isSelectedIndicates whether the row is selected. Available if rowType is "data" or "detail".
key anyThe row's key. Available if the rowType is "data", "detail" or "detailAdaptive".
For plain data, the value of the key depends on the keyExpr property. For hierarchical data, the key is generated automatically or set in the underlying Store of the data source.
The node's hierarchical level.
nodeThe row's node.
rowElementThe row's container. It is an HTML Element or a jQuery Element when you use jQuery.
rowIndexThe row's index. Refer to Column and Row Indexes for more information.
rowTypeThe row's type.
valuesArray<any>
Values displayed in the row cells.
Default Value: null
A function that is executed after a row has been removed from the data source.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description key anyThe key of the row. If a field providing keys is not specified in the data source, the whole data object is considered the key.
errorThe standard Error object defining an error that may occur during removal.
dataThe data of the row.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
In batch
editing mode, if several rows have been removed, this function will be executed for each row individually.
A function that is executed before a row is removed from the data source.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description key anyThe row's key.
dataThe data of the row that should be removed.
cancel |Promise<Boolean> (jQuery or native)
|Promise<void> (jQuery or native)
true, a Promise resolved with true, or a rejected Promise stops row removal.
false or a Promise resolved with false or undefined continues row removal.
The UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
In batch
editing mode, this function is executed for each row individually if several rows should be removed.
This function allows you to intercept row removal and perform additional actions. The following code shows how to use the function parameter's cancel field to prevent or continue removal. In this code, a Promise is assigned to this field. Removal continues if a user confirms it and row validation on the server succeeds (the Promise is resolved); otherwise, removal is prevented (the Promise is rejected):
jQuery$(function(){ $("#treeListContainer").dxTreeList({ // ... onRowRemoving: function(e) { var deferred = $.Deferred(); $.ajax({ url: `https://url/to/your/validation/service/${e.key}`, success: function(validationResult) { if (validationResult.errorText) { deferred.reject(validationResult.errorText); } else { deferred.resolve(false); } }, error: function() { deferred.reject("Data Loading Error"); }, timeout: 5000 }); e.cancel = deferred.promise(); }, }) })Angular
import { DxTreeListModule } from "devextreme-angular"; import { HttpClient, HttpClientModule, HttpParams } from "@angular/common/http"; import { lastValueFrom } from 'rxjs'; export class AppComponent { constructor(private httpClient: HttpClient) { /*...*/ } validateRemove(e) { const isCanceled = new Promise((resolve, reject) => { const request$ = this.httpClient .get(`https://url/to/your/validation/service/${e.key}`); lastValueFrom(request$).then((validationResult) => { if (validationResult.errorText) { reject(validationResult.errorText); } else { resolve(false); } }); }); e.cancel = isCanceled; } }
<dx-tree-list ... (onRowRemoving)="validateRemove($event)"> </dx-tree-list>
// ... import { DxTreeListModule } from 'devextreme-angular'; import { HttpClientModule } from "@angular/common/http"; @NgModule({ imports: [ // ... DxTreeListModule, HttpClientModule ], // ... })Vue
<template> <DxTreeList ... @row-removing="validateRemove"> </DxTreeList> </template> <script> import DxTreeList, { ... } from 'devextreme-vue/tree-list'; // ... export default { components: { DxTreeList, // ... }, // ... methods: { validateRemove(e) { const isCanceled = new Promise((resolve, reject) => { fetch(`https://url/to/your/validation/service/${e.key}`) .then((validationResult) => { if (validationResult.errorText) { reject(validationResult.errorText); } else { resolve(false); } }); }); e.cancel = isCanceled; } }, }; </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList, { ... } from 'devextreme-react/tree-list'; function validateRemove(e) { const isCanceled = new Promise((resolve, reject) => { fetch(`https://url/to/your/validation/service/${e.key}`) .then((validationResult) => { if (validationResult.errorText) { reject(validationResult.errorText); } else { resolve(false); } }); }); e.cancel = isCanceled; } function App() { return ( <TreeList ... onRowRemoving={validateRemove}> // ... </TreeList> ); } export default App;
A function that is executed after a row has been updated in the data source.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description key anyThe key of the row. If a field providing keys is not specified in the data source, the whole data object is considered the key.
errorThe standard Error object defining an error that may occur during updating.
dataThe updated data of the row.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
In batch
editing mode, if several rows have been updated, this function will be executed for each row individually.
A function that is executed before a row is updated in the data source.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description oldDataThe row's old data.
newDataThe row's updated data.
key anyThe row's key.
cancel |Promise<Boolean> (jQuery or native)
|Promise<void> (jQuery or native)
true, a Promise resolved with true, or a rejected Promise stops row updating.
false or a Promise resolved with false or undefined continues row updating.
The UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
This function allows you to intercept row update and perform additional actions. The following code shows how to use the function parameter's cancel field to prevent or continue row update. In this code, a Promise is assigned to this field. Row update continues if a user confirms it and row data validation on the server succeeds (the Promise is resolved); otherwise, row update is prevented (the Promise is rejected).
jQuery$(function(){ $("#treeListContainer").dxTreeList({ // ... onRowUpdating: function(e) { const deferred = $.Deferred(); const promptPromise = DevExpress.ui.dialog.confirm("Are you sure?", "Confirm changes"); promptPromise.done((dialogResult) => { if (dialogResult) { $.ajax({ url: "https://url/to/your/validation/service", dataType: "json", data: e.newData, success: function(validationResult) { if (validationResult.errorText) { deferred.reject(validationResult.errorText); } else { deferred.resolve(false); } }, error: function() { deferred.reject("Data Loading Error"); }, timeout: 5000 }); } else { deferred.resolve(true); } }); e.cancel = deferred.promise(); } }) })Angular
import { HttpClient, HttpClientModule, HttpParams } from "@angular/common/http"; import { confirm } from 'devextreme/ui/dialog'; import { lastValueFrom } from 'rxjs'; // ... export class AppComponent { constructor(private httpClient: HttpClient) { /*...*/ } async updateRow(e) { try { const dialogResult = await this.confirmAsync("Are you sure?", "Confirm changes"); if (dialogResult) { let params = new HttpParams(); for (let key in e.newData) { params = params.set(key, e.newData[key]); } const validationResult = await lastValueFrom(this.httpClient.get("https://url/to/your/validation/service", { params })); if (validationResult.errorText) { throw validationResult.errorText; } else { e.cancel = false; } } else { e.cancel = true; } } catch (error) { console.error("Validation or confirmation error", error); e.cancel = Promise.reject(error); } } private confirmAsync(message: string, title?: string): Promise<boolean> { return new Promise<boolean>((resolve) => { const dialogResult = confirm(message, title); resolve(dialogResult); }); } }
<dx-tree-list ... (onRowUpdating)="updateRow($event)"> </dx-tree-list>
// ... import { DxTreeListModule } from 'devextreme-angular'; import { HttpClientModule } from "@angular/common/http"; @NgModule({ imports: [ // ... DxTreeListModule, HttpClientModule ], // ... })Vue
<template> <DxTreeList ... @row-updating="updateRow"> </DxTreeList> </template> <script> import DxTreeList, { ... } from 'devextreme-vue/tree-list'; import { confirm } from 'devextreme/ui/dialog'; // ... export default { components: { DxTreeList, // ... }, // ... methods: { updateRow(e) { const isCanceled = new Promise((resolve, reject) => { const promptPromise = confirm("Are you sure?", "Confirm changes"); promptPromise.then((dialogResult) => { if (dialogResult) { let params = new HttpParams(); for (let key in e.newData) { params = params.set(key, e.newData[key]); } fetch(`https://url/to/your/validation/service${params}`) .then((validationResult) => { if (validationResult.errorText) { reject(validationResult.errorText); } else { resolve(false); } }); } else { return resolve(true); } }); }); e.cancel = isCanceled; } }, }; </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import { confirm } from 'devextreme/ui/dialog'; import TreeList, { ... } from 'devextreme-react/tree-list'; function updateRow(e) { const isCanceled = new Promise((resolve, reject) => { const promptPromise = confirm("Are you sure?", "Confirm changes"); promptPromise.then((dialogResult) => { if (dialogResult) { let params = new HttpParams(); for (let key in e.newData) { params = params.set(key, e.newData[key]); } fetch(`https://url/to/your/validation/service${params}`) .then((validationResult) => { if (validationResult.errorText) { reject(validationResult.errorText); } else { resolve(false); } }); } else { return resolve(true); } }); }); e.cancel = isCanceled; } function App() { return ( <TreeList ... onRowUpdating={updateRow}> // ... </TreeList> ); } export default App;
You can use this function to change e.newData
values, but do not use it to implement custom update logic. For this purpose, you can implement the onSaving or CustomStore's update function.
In batch editing mode, this function is executed for each row individually if several rows should be updated.
A function that is executed after cells in a row are validated against validation rules.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description promisePromise<void> (jQuery or native)
Assign a Promise to this field to perform an asynchronous operation, such as a request to a server.
oldData anyThe data of the validated row before changes.
newDataThe data of the validated row after changes.
key anyThe key of the row. If a field providing keys is not specified in the data source, the whole data object is considered the key.
isValidIndicates whether data in all row cells satisfies the validation rules.
errorTextAn error message to be displayed.
brokenRulesAn array of broken rules. The structure of rule objects is described in the Validation Rules section.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
Use this function to perform operations before messages about failed validation are shown. For instance, you can run additional checks and change the isValid function parameter to change the validation result. You can also change the errorText parameter to correct the error message.
The following code illustrates how to validate an email address on the server and display an error row with a custom error text if the validation fails:
jQuery$(function() { $("#treeListContainer").dxTreeList({ // ... onRowValidating: function(e) { if(e.newData.Email) { e.promise = checkEmail(e.newData.Email) .done(function(result) { e.errorText = result.errorText; e.isValid = result.isValid; }); } } }); }); function checkEmail(email) { return $.ajax({ // The url returns { errorText: "The Email address you entered already exists.", isValid: false } url: "https://www.mywebsite.com/api/checkEmail", dataType: "json", data: { email: email } }); }Angular
<dx-tree-list ... (onRowValidating)="onRowValidating($event)"> </dx-tree-list>
import { Component } from '@angular/core'; import { HttpClient, HttpParams } from '@angular/common/http'; import { lastValueFrom } from 'rxjs'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { constructor(@Inject(HttpClient) http: HttpClient) { this.checkEmail = this.checkEmail.bind(this); } onRowValidating(e) { if(e.newData.Email) { e.promise = this.checkEmail(e.newData.Email) .then((result: any) => { // "result" is { errorText: "The Email address you entered already exists.", isValid: false } e.errorText = result.errorText; e.isValid = result.isValid; }); } } checkEmail(email) { const params = new HttpParams().set("email", email); return lastValueFrom( this.http.get("https://www.mywebsite.com/api/checkEmail", { params }) ); } }
import { BrowserModule } from '@angular/platform-browser'; import { NgModule, Component } from '@angular/core'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; import { DxTreeListModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, HttpClientModule, DxTreeListModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }Vue
<template> <DxTreeList ... @row-validating="onRowValidating"> </DxTreeList> </template> <script> import 'devextreme/dist/css/dx.light.css'; import DxTreeList from 'devextreme-vue/tree-list'; import 'whatwg-fetch'; export default { components: { DxTreeList }, // ... methods: { onRowValidating(e) { if(e.newData.Email) { e.promise = this.checkEmail(e.newData.Email) .then((result: any) => { // "result" is { errorText: "The Email address you entered already exists.", isValid: false } e.errorText = result.errorText; e.isValid = result.isValid; }); } }, checkEmail(email) { let params = '?' + 'email=' + email; return fetch("https://www.mywebsite.com/api/checkEmail${params}"); } } } </script>React
import React from 'react'; import 'devextreme/dist/css/dx.light.css'; import TreeList from 'devextreme-react/tree-list'; import 'whatwg-fetch'; class App extends React.Component { constructor(props) { super(props); this.onRowValidating = this.onRowValidating.bind(this); } onRowValidating(e) { if(e.newData.Email) { e.promise = this.checkEmail(e.newData.Email) .then((result: any) => { // "result" is { errorText: "The Email address you entered already exists.", isValid: false } e.errorText = result.errorText; e.isValid = result.isValid; }); } } checkEmail(email) { let params = '?' + 'email=' + email; return fetch("https://www.mywebsite.com/api/checkEmail${params}"); } render() { return ( <TreeList ... onRowValidating={this.onRowValidating}> </TreeList> ); } } export default App;ASP.NET MVC Controls
@(Html.DevExtreme().TreeList() // ... .OnRowValidating("onRowValidating") ) <script type="text/javascript"> function onRowValidating(e) { if(e.newData.Email) { e.promise = checkEmail(e.newData.Email) .done(function(result) { e.errorText = result.errorText; e.isValid = result.isValid; }); } } function checkEmail(email) { return $.ajax({ // The url returns { errorText: "The Email address you entered already exists.", isValid: false } url: "https://www.mywebsite.com/api/checkEmail", dataType: "json", data: { email: email } }); } </script>
In batch
editing mode, if changes in several rows are committed simultaneously, this function is executed for each row.
A function that is executed after row changes are saved.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
A function that is executed before pending row changes are saved.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description promisePromise<void> (jQuery or native)
Assign a Promise to this field to perform an asynchronous operation, such as a request to a server.
changesArray<DataChange>
Pending row changes; a copy of the editing.changes array.
cancelSet this field to true if the default saving logic should be disabled.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
A save operation can be initiated from the UI (with the Save button) or programatically (with the saveEditData() method).
A function that is executed after selecting a row or clearing its selection.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Name Type Description selectedRowsDataThe data of all selected rows.
Does not include calculated values.
Array<any>
The keys of all selected rows.
currentSelectedRowKeysArray<any>
The keys of the rows that have been selected.
currentDeselectedRowKeysArray<any>
The keys of the rows whose selection has been cleared.
elementThe UI component's container. It is an HTML Element or a jQuery Element when you use jQuery.
componentThe UI component's instance.
Default Value: null
This function has the following specifics:
A function that is executed before the toolbar is created.
Function parameters:Information about the event that caused the function's execution.
Object structure:
Default Value: null
If you use DevExtreme ASP.NET components or JQuery in your application, specify this property to get the component's instance. In Angular, Vue, or React, use the toolbar property instead.
jQueryThe following code adds a refresh button to the toolbar:
$(function() { $("#container").dxTreeList({ // ... onToolbarPreparing: function(e) { let dataGrid = e.component; e.toolbarOptions.items.unshift({ location: "after", widget: "dxButton", options: { icon: "refresh", onClick: function() { dataGrid.refresh(); } } }); } }); });
Configures the pager.
Selector: Pager
Type: Pager
Function parameters:allowedPageSizes:
Object structure:
Name Type Description |Specifies the available page sizes in the page size selector.
visible:
Object structure:
Name Type Description |Specifies whether the pager is visible.
The pager is an element that allows users to navigate through pages and change their size at runtime. The pager consists of the page navigator and several optional elements: the page size selector, navigation buttons, and page information.
See AlsoAn object that configures paging.
Paging allows the UI component to load data in portions instead of loading it simultaneously. To enable paging, set the paging.enabled property to true.
Users can switch between pages and change paging settings using the pager or they can scroll the pages. Paging settings apply with any scrolling mode.
See AlsoSpecifies which data field provides parent keys.
Default Value: 'parentId'
Notifies the TreeList of the server's data processing operations. Applies only if data has a plain structure.
Selector: RemoteOperations
Default Value: 'auto'
Server-side data processing improves the UI component's performance on large datasets. When the server does not implement particular operations (and/or the corresponding remoteOperations fields are false) they are executed on the client. Note that the UI component may send queries to the server while executing a client-side operation.
The following table lists the possible remoteOperations configurations and the operations the server should implement. The server should also implement additional operations depending on the used UI component functionality.
Setting Required server-side operations Additional server-side operationsremoteOperations: { filtering: true }
filtering - remoteOperations: { sorting: true }
sorting filtering* remoteOperations: { grouping: true }
grouping, filtering sorting*
Filtering and sorting are performed on the server side for the
ODataStore, but you can change them to the client side by setting the corresponding
remoteOperationsfields to
false. Other operations are always client-side.
When operations are performed on the server side, the TreeList does not support:
Web API Service Demo Load Data on Demand Demo
See AlsoSpecifies whether to repaint only those cells whose data changed.
Specifies the root node's identifier. Applies if dataStructure is "plain".
Type: any
Default Value: 0
Specifies whether rows should be shaded differently.
All rows are monochrome without any visual distinctions by default. If you set this property to true, ordinary-looking rows will alternate with slightly shaded ones.
Configures row reordering using drag and drop gestures.
To learn how to configure drag and drop functionality for multiple rows, refer to the following example:
To learn how to configure drag and drop functionality for multiple rows between grids, refer to the following example:
Switches the UI component to a right-to-left representation.
When this property is set to true, the UI component text flows from right to left, and the layout of elements is reversed. To switch the entire application/site to the right-to-left representation, assign true to the rtlEnabled field of the object passed to the DevExpress.config(config) method.
DevExpress.config({ rtlEnabled: true });
DataGrid Demo Navigation UI Demo Editors Demo
Configures scrolling.
Scrolling allows a user to browse data left outside the current viewport. The UI component provides several scrolling modes detailed in the mode property description.
See AlsoConfigures the search panel.
Allows you to select rows or determine which rows are selected.
Configures runtime selection.
Specifies whether the outer borders of the UI component are visible.
Specifies whether column headers are visible.
Specifies whether vertical lines that separate one column from another are visible.
Default Value: true, false (Fluent, Material)
If you use the Android or iOS theme, specifying this property doesn't affect anything. These themes avoid displaying column lines in order to provide a native look for the UI component. In case you still require the column lines to be displayed, choose
another theme.
See AlsoSpecifies whether horizontal lines that separate one row from another are visible.
Default Value: false, true (Fluent, Material, iOS)
Configures runtime sorting.
A user can sort rows by values of a single or multiple columns depending on the value of the sorting.mode property.
To apply sorting to a column, a user clicks its header or selects a command from the context menu.
Note that rows are sorted within their hierarchical level.
See AlsoConfigures state storing.
State storing enables the UI component to save applied settings and restore them the next time the UI component is loaded. Assign true to the stateStoring.enabled property to enable this functionality.
State storing saves the following properties:
See AlsoSpecifies whether to show only relevant values in the header filter and filter row.
The following table shows how the component behaves when you assign different values to this property. The 'State' column is filtered by the 'Alabama' value. If you set the syncLookupFilterValues to false
, the 'City' column's header filter and filter row display all cities instead of showing cities within Alabama only.
When syncLookupFilterValues and remoteOperations.filtering are both enabled, TreeList performs additional server requests with the group
parameter to fetch filter values for lookup columns. The component performs these group
requests when users open a lookup column filter editor after applying other column filters.
To enable pagination in the filter row and header filter of lookup columns when syncLookupFilterValues is true
, specify columns[].calculateDisplayValue along with DataSource.paginate. When using a remote data source, enable remoteOperations.groupPaging to configure remote pagination.
If the filterPanel is visible and columns.headerFilter.dataSource or columns.lookup.dataSource are specified, disable syncLookupFilterValues to ensure the filterPanel displays data correctly.
If a lookup data source lacks fields corresponding to column data, the header filter may load incorrectly. To prevent this issue, disable syncLookupFilterValues or the DataSource.paginate property of the lookup data source.
Specifies the number of the element when the Tab key is used for navigating.
The value of this property will be passed to the tabindex
attribute of the HTML element that underlies the UI component.
Configures the toolbar.
Selector: Toolbar
Default Value: undefined
Specifies whether to enable two-way data binding.
Two-way data binding ensures that the UI tracks changes made in the data source by a 3rd-party component, and vice versa. This way, the UI component and its data source stay synchronized.
If you implement two-way data binding in the UI component on your own using the cellTemplate and/or editCellTemplate properties, make sure to set the twoWayBindingEnabled property to false.
Specifies whether the UI component is visible.
Specifies the UI component's width.
This property accepts a value of one of the following types:
Number
The width in pixels.
String
A CSS-accepted measurement of width. For example, "55px"
, "20vw"
, "80%"
, "auto"
, "inherit"
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4