Editing

NOTE
Editing does not work with hierarchical data sources out of the box, but you can use the code sample from this KB to implement it.

Remote CRUD Operations Demo

User Interaction

The TreeList UI component allows a user to add, delete and update data. Assign true to the corresponding field of the editing object to enable an operation. You can set a column's allowEditing property to false if its data should not be edited.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        editing: {
            allowUpdating: true, 
            allowAdding: true, 
            allowDeleting: true 
        },
        columns: [
            { dataField: 'id', allowEditing: false },
            // ...
        ]
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxo-editing
        [allowUpdating]="true"
        [allowAdding]="true"
        [allowDeleting]="true">
    </dxo-editing>
    <dxi-column dataField="id" [allowEditing]="false"></dxi-column>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxEditing
            :allow-updating="true"
            :allow-adding="true"
            :allow-deleting="true"
        />
        <DxColumn data-field="id" :allow-editing="false" />
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxTreeList, {
    DxEditing,
    DxColumn
} from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList,
        DxEditing,
        DxColumn
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.light.css';

import TreeList, {
    Editing,
    Column
} from 'devextreme-react/tree-list';

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Editing
                    allowUpdating={true}
                    allowAdding={true}
                    allowDeleting={true}
                />
                <Column dataField="id" allowEditing={false} />
            </TreeList>
        );
    }
}
export default App;

With the TreeList you can edit data in several modes. Use the editing.mode property to specify it.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        editing: {
            mode: 'row' // 'batch' | 'cell' | 'form' | 'popup'
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxo-editing
        mode="row"> <!-- 'batch' | 'cell' | 'form' | 'popup' -->
    </dxo-editing>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxEditing ...
            mode="row" /> <!-- 'batch' | 'cell' | 'form' | 'popup' -->
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList, {
    DxEditing
} from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList,
        DxEditing
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.light.css';

import TreeList, {
    Editing
} from 'devextreme-react/tree-list';

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Editing ...
                    mode="row" /> {/* 'batch' | 'cell' | 'form' | 'popup' */}
            </TreeList>
        );
    }
}
export default App;

The following sections detail the TreeList's appearance and behavior in each editing mode.

Row Mode

In this mode a user edits data row by row. When a user clicks an "Edit" button, the corresponding row enters the editing state, and the "Save" and "Cancel" buttons appear in the edit column. The UI component saves changes only if the "Save" button is clicked. If a user starts editing another row, sorts or filters data, it discards the changes.

DevExtreme HTML5 JavaScript jQuery Angular Knockout UI component TreeList Editing Row Mode Editing State

Clicking the "Delete" button invokes the confirmation dialog that allows a user to cancel row deletion. Use the confirmDelete property to hide this dialog.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        editing: {
            // ...
            mode: 'row',
            allowDeleting: true,
            confirmDelete: false
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxo-editing 
        mode="row"
        [confirmDelete]="false"
        [allowDeleting]="true">
    </dxo-editing>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxEditing
            mode="row"
            :allow-deleting="true"
            :confirm-delete="false"
        />
    </DxTreeList>
</template>

<script>
import { DxTreeList, DxEditing } from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList, 
        DxEditing
    },
    data() {}
}
</script>
React
App.js
import React from 'react';

import { TreeList, Editing } from 'devextreme-react/tree-list';

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Editing
                    mode="row"
                    confirmDelete={false}
                    allowDeleting={true} 
                />
            </TreeList>
        );
    }
}
export default App;

View Demo

See Also

Cell Mode

In the cell mode, a user edits data cell by cell. Changes are saved once a cell loses the focus, or discarded if a user presses Esc. An added row is saved only when the focus is shifted from it. Choose this mode if any changes should be saved to the data source immediately.

DevExtreme HTML5 JavaScript jQuery Angular Knockout UI component TreeList Editing Cell Mode

If you validate data, a cell is locked in the editing state until a user enters a valid value or clicks the "Cancel Changes" button.

DevExtreme HTML5 JavaScript jQuery Angular Knockout UI component TreeList Editing Cell Mode Validation

Clicking the "Delete" button invokes the confirmation dialog that allows a user to cancel row deletion. Use the confirmDelete property to hide this dialog.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        editing: {
            mode: 'cell', 
            confirmDelete: false
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxo-editing 
        mode="cell"
        [confirmDelete]="false"
        [allowDeleting]="true">
    </dxo-editing>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxEditing
            mode="row"
            :allow-deleting="true"
            :confirm-delete="false"
        />
    </DxTreeList>
</template>

<script>
import { DxTreeList, DxEditing } from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList, 
        DxEditing
    },
    data() {}
}
</script>
React
App.js
import React from 'react';

import { TreeList, Editing } from 'devextreme-react/tree-list';

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Editing
                    mode="row"
                    confirmDelete={false}
                    allowDeleting={true} 
                />
            </TreeList>
        );
    }
}
export default App;

View Demo

See Also

Batch Mode

In the batch mode, like in the cell mode, a user edits data cell by cell. However, in this mode the UI component stores changes in a buffer until a user clicks the global "Save" button instead of saving them immediately. This mode is useful when you need to defer saving multiple changes.

DevExtreme HTML5 JavaScript jQuery Angular Knockout UI component TreeList Editing Batch Mode

When a user clicks a "Delete" button in a row, the UI component only marks the row as deleted. Users can restore this row by clicking the "Undelete" button if they have not saved the changes yet. They can also discard all unsaved changes by clicking the "Revert" button.

DevExtreme HTML5 JavaScript jQuery Angular Knockout UI component TreeList Editing Batch Mode Deletion

View Demo

See Also

Form Mode

In form edit mode, row cells become editable form fields. Form fields are sorted like columns in the columns array.

DevExtreme HTML5 JavaScript jQuery Angular Knockout UI component TreeList Editing Form Mode

Configure the form using the editing.form object. The TreeList uses the DevExtreme Form UI component, so you can specify any Form properties in this object except those listed in its description.

For example, you can specify the items array to reorder editable fields (or "simple items", as they are called in the Form UI component), or organize them in groups and tabs.

In the following code, the items with the specified dataField are simple items. Identical dataFields connect a simple item with a column:

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        editing: {
            allowUpdating: true,
            mode: "form",
            form: {
                items: [{
                    itemType: "group",
                    caption: "Personal Data",
                    items: [
                        { dataField: "Prefix" },
                        { dataField: "Full_Name" },
                        { dataField: "Position" },
                        { dataField: "Duties", editorType: "dxTextArea" }
                    ]
                    // or just
                    // items: ["Prefix", "Full_Name", "Position"]
                }, {
                    itemType: "group",
                    caption: "Contacts",
                    items: ["Email", "Skype"]
                }]
            }
        },
        columns: [ 
            { dataField: "Full_Name" }, 
            { dataField: "Prefix" },
            { dataField: "Position" },
            { dataField: "Duties" },
            { dataField: "Email" },
            { dataField: "Skype" } 
        ]
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxo-editing
        [allowUpdating]="true"
        mode="form">
        <dxo-form>
            <dxi-item itemType="group" caption="Personal Data">
                <dxi-item dataField="Prefix"></dxi-item>
                <dxi-item dataField="Full_Name"></dxi-item>
                <dxi-item dataField="Position"></dxi-item>
                <dxi-item dataField="Duties" editorType="dxTextArea"></dxi-item>
            </dxi-item>
            <dxi-item itemType="group" caption="Contacts">
                <dxi-item dataField="Email"></dxi-item>
                <dxi-item dataField="Skype"></dxi-item>
            </dxi-item>
        </dxo-form>
    </dxo-editing>
    <dxi-column dataField="Full_Name"></dxi-column>
    <dxi-column dataField="Prefix"></dxi-column>
    <dxi-column dataField="Position"></dxi-column>
    <dxi-column dataField="Duties"></dxi-column>
    <dxi-column dataField="Email"></dxi-column>
    <dxi-column dataField="Skype"></dxi-column>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxEditing
            :allow-updating="true"
            mode="form">
            <DxForm>
                <DxGroupItem caption="Personal Data">
                    <DxSimpleItem data-field="Prefix" />
                    <DxSimpleItem data-field="Full_Name" />
                    <DxSimpleItem data-field="Position" />
                    <DxSimpleItem data-field="Duties" editor-type="dxTextArea" />
                </DxGroupItem>
                <DxGroupItem caption="Contacts">
                    <DxSimpleItem data-field="Email" />
                    <DxSimpleItem data-field="Skype" />
                </DxGroupItem>
            </DxForm>
        </DxEditing>
        <DxColumn data-field="Full_Name" />
        <DxColumn data-field="Prefix" />
        <DxColumn data-field="Position" />
        <DxColumn data-field="Duties" />
        <DxColumn data-field="Email" />
        <DxColumn data-field="Skype" />
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxTreeList, {
    DxEditing,
    DxForm,
    DxColumn
} from 'devextreme-vue/tree-list';

import {
    DxSimpleItem,
    DxGroupItem
} from 'devextreme-vue/form';

import 'devextreme-vue/text-area';

export default {
    components: {
        DxTreeList,
        DxEditing,
        DxForm,
        DxColumn,
        DxSimpleItem,
        DxGroupItem
    }
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.light.css';

import TreeList, {
    Editing,
    Form,
    Column
} from 'devextreme-react/tree-list';

import {
    SimpleItem,
    GroupItem
} from 'devextreme-react/form';

import 'devextreme-react/text-area';

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Editing
                    allowUpdating={true}
                    mode="form">
                    <Form>
                        <GroupItem caption="Personal Data">
                            <SimpleItem dataField="Prefix" />
                            <SimpleItem dataField="Full_Name" />
                            <SimpleItem dataField="Position" />
                            <SimpleItem dataField="Duties" editorType="dxTextArea" />
                        </GroupItem>
                        <GroupItem caption="Contacts">
                            <SimpleItem dataField="Email" />
                            <SimpleItem dataField="Skype" />
                        </GroupItem>
                    </Form>
                </Editing>
                <Column dataField="Full_Name" />
                <Column dataField="Prefix" />
                <Column dataField="Position" />
                <Column dataField="Duties" />
                <Column dataField="Email" />
                <Column dataField="Skype" />
            </TreeList>
        );
    }
}
export default App;
ASP.NET MVC Controls
Razor C#
@(Html.DevExtreme().TreeList()
    // ...
    .Editing(e => e
        .AllowUpdating(true)
        .Mode(GridEditMode.Form)
        .Form(f => f
            .Items(i => {
                i.AddGroup()
                    .Caption("Personal Data")
                    .Items(groupItems => {
                        groupItems.AddSimple().DataField("Prefix");
                        groupItems.AddSimple().DataField("Full_Name");
                        groupItems.AddSimple().DataField("Position");
                        groupItems.AddSimple().DataField("Duties")
                            .Editor(e => e.TextArea());
                    });
                i.AddGroup()
                    .Caption("Contacts")
                    .Items(groupItems => {
                        groupItems.AddSimple().DataField("Email");
                        groupItems.AddSimple().DataField("Skype");
                    });
            })
        )
    )
    .Columns(cols => {
        cols.Add().DataField("Full_Name");
        cols.Add().DataField("Prefix");
        cols.Add().DataField("Position");
        cols.Add().DataField("Duties");
        cols.Add().DataField("Email");
        cols.Add().DataField("Skype");
    })
)
See Also

You can use a column's formItem object to customize an individual simple item. See an example in its description.

If you need to validate form values, specify validation rules as described in the Data Validation article.

View Demo

Popup Mode

The popup mode is the form mode with the form placed in a popup window.

DevExtreme HTML5 JavaScript jQuery Angular Knockout UI component TreeList Editing Popup Mode

Use the editing.popup object to customize the popup window. This object can contain the Popup UI component's fields. However, you should refer to the popup object's description for information on restrictions that apply.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        editing: {
            allowUpdating: true,
            mode: "popup",
            form: {
                labelLocation: "top"
            },
            popup: {
                showTitle: true,
                title: "Row in the editing state"
            }
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxo-editing
        [allowUpdating]="true"
        mode="popup">
        <dxo-form labelLocation="top"></dxo-form>
        <dxo-popup [showTitle]="true" title="Row in the editing state"></dxo-popup>
    </dxo-editing>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxEditing
            :allow-updating="true"
            mode="popup">
            <DxForm
                label-location="top"
            />
            <DxPopup
                :show-title="true"
                title="Row in the editing state"
            />
        </DxEditing>
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxTreeList, {
    DxEditing,
    DxForm,
    DxPopup
} from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList,
        DxEditing,
        DxForm,
        DxPopup
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.light.css';

import TreeList, {
    Editing,
    Form,
    Popup
} from 'devextreme-react/tree-list';

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Editing
                    allowUpdating={true}
                    mode="popup">
                    <Form
                        labelLocation="top"
                    />
                    <Popup
                        showTitle={true}
                        title="Row in the editing state"
                    />
                </Editing>
            </TreeList>
        );
    }
}
export default App;

Since the popup and form modes are very similar, you can use the same columns.formItem and editing.form properties to customize items and layout in both modes. See the Form Mode topic for more details on form customization.

View Demo

See Also

API

NOTE
Editing does not work with hierarchical data sources out of the box, but you can use the code sample from this KB to implement it.

Add

Use the addRow() method to add an empty row.

jQuery
JavaScript
$("#treeListContainer").dxTreeList("addRow");
Angular
TypeScript
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;
    addRow () {
       this.treeList.instance.addRow();
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        ref="myTreeList">
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';

import DxTreeList from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList
    },
    methods: {
        addNewRow() {
            this.$refs['myTreeList'].instance.addRow();
        }
    }
}
</script>
React
App.js
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.addNewRow = this.addNewRow.bind(this);
    }

    addNewRow() {
        this.treeListRef.current.instance.addRow();
    }

    render() {
        return (
            <TreeList ...
                ref={this.treeListRef}>
            </TreeList>
        );
    }
}
export default App;

You can specify initial values for a newly added row in the onInitNewRow event handler.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        columns: [{
            dataField: "Hire_Date",
            dataType: "date"
        },
            // ...
        ],
        onInitNewRow: function(e) {
            e.data.Hire_Date = new Date();
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ...
    (onInitNewRow)="onInitNewRow($event)">
    <dxi-column dataField="Hire_Date" dataType="date"></dxi-column>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    onInitNewRow (e) {
        e.data.Hire_Date = new Date();
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        @init-new-row="setHireDate">
        <DxColumn data-field="Hire_Date" data-type="date" />
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList, {
    DxColumn
} from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList,
        DxColumn
    },
    methods: {
        setHireDate(e) {
            e.data.Hire_Date = new Date();
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList, {
    Column
} from 'devextreme-react/tree-list';

class App extends React.Component {
    setHireDate(e) {
        e.data.Hire_Date = new Date();
    }

    render() {
        return (
            <TreeList ...
                onInitNewRow={this.setHireDate}>
                <Column dataField="Hire_Date" dataType="date" />
            </TreeList>
        );
    }
}
export default App;
See Also

Update

The cellValue (rowIndex, visibleColumnIndex, value) method updates a cell's value. This cell can be located using its row and column indexes. If the cell's data field is known, you can pass it instead of the column index. After a value is updated, save it to the data source by calling the saveEditData() method.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({ ... });

    $("#updateCellButton").dxButton({
        text: "Update Cell",
        onClick: function() {
            $("#treeListContainer").dxTreeList("cellValue", 1, "Position", "CTO");
            $("#treeListContainer").dxTreeList("saveEditData");
        }
    });
});
Angular
TypeScript
HTML
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxTreeListComponent, { static: false }) treeList: DxTreeListComponent;
    // Prior to Angular 8
    // @ViewChild(DxTreeListComponent) treeList: DxTreeListComponent;
    updateCell () {
        this.treeList.instance.cellValue(1, "Position", "CTO");
        this.treeList.instance.saveEditData();
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
<dx-tree-list ... ></dx-tree-list>
<dx-button
    text="Update Cell"
    (onClick)="updateCell()">
</dx-button>
Vue
App.vue
<template>
    <div>
        <DxTreeList ...
            :ref="treeListRefKey">
        </DxTreeList>
        <DxButton
            text="Update Cell"
            @click="updateCell"
        />
    </div>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList from 'devextreme-vue/tree-list';
import DxButton from 'devextreme-vue/button';

const treeListRefKey = 'myTreeList';

export default {
    components: {
        DxTreeList,
        DxButton
    },
    data: function() {
        return {
            treeListRefKey
        }
    },
    methods: {
        updateCell() {
            this.treeList.cellValue(1, "Position", "CTO");
            this.treeList.saveEditData();
        }
    },
    computed: {
        treeList: function() {
            return this.$refs[treeListRefKey].instance;
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList from 'devextreme-react/tree-list';
import Button from 'devextreme-react/button';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.treeListRef = React.createRef();
        this.updateCell = this.updateCell.bind(this);
    }

    get treeList() {
        return this.treeListRef.current.instance;
    }

    updateCell() {
        this.treeList.cellValue(1, "Position", "CTO");
        this.treeList.saveEditData();
    }

    render() {
        return (
            <React.Fragment>
                <TreeList ...
                    ref={this.treeListRef}>
                </TreeList>
                <Button
                    text="Update Cell"
                    onClick={this.updateCell}
                />
            </React.Fragment>
        );
    }
}
export default App;

The TreeList UI component allows you to process an updated cell value in the columns.setCellValue function before this value is saved to the data source. Refer to the function's description for an example.

Call the hasEditData() to check if there are any unsaved changes. You can save or cancel them using the saveEditData() or cancelEditData() method, respectively.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({ ... });

    $("#saveChangesButton").dxButton({
        text: "Save changes",
        onClick: function() {
            var treeList = $("#treeListContainer").dxTreeList("instance");
            if(treeList.hasEditData()) {
                treeList.saveEditData().then(() => {
                    if(!treeList.hasEditData()) {
                        // Saved successfully
                    } else {
                        // Saving failed
                    }
                });
            }
        }
    });
});
Angular
TypeScript
HTML
import { DxTreeListModule, DxButtonModule } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxTreeListComponent, { static: false }) treeList: DxTreeListComponent;
    // Prior to Angular 8
    // @ViewChild(DxTreeListComponent) treeList: DxTreeListComponent;
    saveEditData() {
        if(this.treeList.instance.hasEditData()) {
            this.treeList.instance.saveEditData().then(() => {
                if(!this.treeList.instance.hasEditData()) {
                    // Saved successfully
                } else {
                    // Saving failed
                }
            });
        }
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule,
        DxButtonModule
    ],
    // ...
})
<dx-tree-list ... ></dx-tree-list>
<dx-button
    text="Save changes"
    (onClick)="saveEditData()">
</dx-button>
Vue
App.vue
<template>
    <div>
        <DxTreeList ...
            :ref="treeListRefKey">
        </DxTreeList>
        <DxButton
            text="Save changes"
            @click="saveChanges"
        />
    </div>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList from 'devextreme-vue/tree-list';
import DxButton from 'devextreme-vue/button';

const treeListRefKey = 'myTreeList';

export default {
    components: {
        DxTreeList,
        DxButton
    },
    data: function() {
        return {
            treeListRefKey
        }
    },
    methods: {
        saveChanges() {
            if(this.treeList.hasEditData()) {
                this.treeList.saveEditData().then(() => {
                    if(!this.treeList.hasEditData()) {
                        // Saved successfully
                    } else {
                        // Saving failed
                    }
                });
            }
        }
    },
    computed: {
        treeList: function() {
            return this.$refs[treeListRefKey].instance;
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList from 'devextreme-react/tree-list';
import Button from 'devextreme-react/button';

class App extends React.Component {
    constructor(props) {
        super(props);
        this.treeListRef = React.createRef();
        this.saveChanges = this.saveChanges.bind(this);
    }

    get treeList() {
        return this.treeListRef.current.instance;
    }

    saveChanges() {
        if(this.treeList.hasEditData()) {
            this.treeList.saveEditData().then(() => {
                if(!this.treeList.hasEditData()) {
                    // Saved successfully
                } else {
                    // Saving failed
                }
            });
        }
    }

    render() {
        return (
            <React.Fragment>
                <TreeList ...
                    ref={this.treeListRef}>
                </TreeList>
                <Button
                    text="Save changes"
                    onClick={this.saveChanges}
                />
            </React.Fragment>
        );
    }
}
export default App;
See Also

Delete

Call the deleteRow(rowIndex) method to delete a specific row from the data source. This method invokes a confirmation dialog that allows a user to cancel deletion. The confirmDelete property allows you to hide this dialog instantly deleting the selected row from the data source.

jQuery
JavaScript
$(function() {
    var treeList = $("#treeListContainer").dxTreeList({
        // ...
        editing: {
            mode: "row", 
            allowDeleting: true,
            confirmDelete: false
        }
    }).dxTreeList("instance");

    $("#deleteRowButton").dxButton({
        text: "Delete Row",
        onClick: function() {
            // Deletes the second row
            treeList.deleteRow(1);
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list>
    <dxo-editing 
        mode="row"
        [confirmDelete]="false"
        [allowDeleting]="true">
    </dxo-editing>
</dx-tree-list>
<dx-button
    text="Delete Row"
    (onClick)="deleteRow()">
</dx-button>
import { DxTreeListModule, DxButtonModule } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxTreeListComponent, { static: false }) treeList: DxTreeListComponent;
    // Prior to Angular 8
    // @ViewChild(DxTreeListComponent) treeList: DxTreeListComponent;
    deleteRow () {
        // Deletes the second row
        this.treeList.instance.deleteRow(1);
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule,
        DxButtonModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList
        ref="treeList">
        <DxEditing
            mode="row"
            :allow-deleting="true"
            :confirm-delete="false"
        />
    </DxTreeList>
    <DxButton
        text="Delete Row"
        @click="deleteRow"
    />
</template>

<script>
import { DxTreeList, DxEditing } from 'devextreme-vue/tree-list';

import DxButton from 'devextreme-vue/button';

export default {
    components: {
        DxTreeList, 
        DxEditing,
        DxButton
    },
    methods: {
        deleteRow() {
            this.$refs.treeList.instance.deleteRow(1);
        }
    },
    data() {}
}
</script>
React
App.js
import React from 'react';

import { TreeList, Editing } from 'devextreme-react/tree-list';
import Button from 'devextreme-react/button';

class App extends React.Component {
    constructor(props) {
        super(props);

        this.treeListRef = React.createRef();
        this.deleteRow = this.deleteRow.bind(this);
    }
    get treeList() {
        return this.treeListRef.current.instance;
    }

    deleteRow() {
        this.treeList.deleteRow(1);
    }

    render() {
        return (
            <TreeList  
                ref={this.treeListRef}>
                <Editing
                    mode="row"
                    confirmDelete={false}
                    allowDeleting={true} 
                />
            </TreeList>
            <Button
                text="Delete Row"
                onClick={this.deleteRow}
            />
        );
    }
}
export default App;

Note that in the batch mode a row is only marked as deleted. To save changes, call the saveEditData() method. Calling the undeleteRow(rowIndex) method cancels row deletion.


jQuery
JavaScript
$("#treeListContainer").dxTreeList("undeleteRow", 1);
Angular
TypeScript
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxTreeListComponent, { static: false }) treeList: DxTreeListComponent;
    // Prior to Angular 8
    // @ViewChild(DxTreeListComponent) treeList: DxTreeListComponent;
    undeleteRow () {
        this.treeList.instance.undeleteRow(1);
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList
        ref="treeList">
    </DxTreeList>
</template>

<script>
import { DxTreeList } from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList
    },
    methods: {
        undeleteRow() {
            this.$refs.treeList.instance.undeleteRow(1);
        }
    },
    data() {}
}
</script>
React
App.js
import React from 'react';

import { TreeList } from 'devextreme-react/tree-list';

class App extends React.Component {
    constructor(props) {
        super(props);

        this.treeListRef = React.createRef();
        this.undeleteRow = this.undeleteRow.bind(this);
    }
    get treeList() {
        return this.treeListRef.current.instance;
    }

    undeleteRow() {
        this.treeList.undeleteRow(1);
    }

    render() {
        return (
            <TreeList  
                ref={this.treeListRef}
            />
        );
    }
}

export default App;

See Also

Events

The TreeList UI component raises events before and after a row is inserted, updated or removed from the data source. If the event handlers are going to remain unchanged during the UI component's lifetime, assign them to corresponding onEventName properties:

jQuery
JavaScript
$(function(){
    $("#treeListContainer").dxTreeList({
        // ...
        onRowInserting: function(e) {
            // Handler of the "rowInserting" event
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ...
    (onRowInserting)="onRowInserting($event)">
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    onRowInserting (e) {
        // Handler of the "rowInserting" event
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        @row-inserting="onRowInserting">
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList
    },
    methods: {
        onRowInserting(e) {
            // Handler of the "rowInserting" event
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList from 'devextreme-react/tree-list';

class App extends React.Component {
    onRowInserting(e) {
        // Handler of the "rowInserting" event
    }

    render() {
        return (
            <TreeList ...
                onRowInserting={this.onRowInserting}>
            </TreeList>
        );
    }
}
export default App;

If you are going to change the event handlers at runtime, or if you need to attach several handlers to a single event, subscribe to this event using the on(eventName, eventHandler) method. This approach is more typical of jQuery.

JavaScript
var rowUpdatingEventHandler1 = function(e) {
    // First handler of the "rowUpdating" event
};

var rowUpdatingEventHandler2 = function(e) {
    // Second handler of the "rowUpdating" event
};

$("#treeListContainer").dxTreeList("instance")
    .on("rowUpdating", rowUpdatingEventHandler1)
    .on("rowUpdating", rowUpdatingEventHandler2);

In addition, the TreeList raises the initNewRow event when a new row is added and the editingStart event when a row enters the editing state. These events can be handled just like others - using the onEventName property or the on(eventName, eventHandler) method. In the following example, the onInitNewRow event handler specifies initial values for an added row:

jQuery
JavaScript
$(function () {
    $("#treeListContainer").dxTreeList({
        // ...
        onInitNewRow: function(e) { // Handler of the "initNewRow" event
            // Sets an initial value for the "Hire_Date" field
            e.data.Hire_Date = new Date();
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ...
    (onInitNewRow)="onInitNewRow($event)">
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    onInitNewRow (e) { // Handler of the "initNewRow" event
        // Sets an initial value for the "Hire_Date" field
        e.data.Hire_Date = new Date();
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        @init-new-row="onInitNewRow">
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList
    },
    methods: {
        onInitNewRow(e) { // Handler of the "initNewRow" event
            // Sets an initial value for the "Hire_Date" field
            e.data.Hire_Date = new Date();
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList from 'devextreme-react/tree-list';

class App extends React.Component {
    onInitNewRow(e) { // Handler of the "initNewRow" event
        // Sets an initial value for the "Hire_Date" field
        e.data.Hire_Date = new Date();
    }

    render() {
        return (
            <TreeList ...
                onInitNewRow={this.onInitNewRow}>
            </TreeList>
        );
    }
}
export default App;
See Also

Customize Editors

The columns's dataType defines a cell's editor that can be configured using the editorOptions object. However, this object cannot be used to change the editor's type or onValueChanged event handler. Instead, use the onEditorPreparing function as shown in the following code. The function's parameter provides the editorName and editorOptions fields for changing the used editor and its configuration.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        columns: [{
            dataField: "Note",
            editorOptions: {
                height: 200
            }
        }, // ...
        ],
        onEditorPreparing: function(e) {
            if (e.dataField == "Note" && e.parentType === "dataRow") {
                const defaultValueChangeHandler = e.editorOptions.onValueChanged;
                e.editorName = "dxTextArea"; // Change the editor's type
                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
HTML
TypeScript
<dx-tree-list ...
    (onEditorPreparing)="onEditorPreparing($event)">
    <dxi-column
        dataField="Note"
        [editorOptions]="{ height: 200 }">
    </dxi-column>
</dx-tree-list>
import { DxTreeListModule, DxTextAreaModule } from "devextreme-angular";
// ...
export class AppComponent {
    onEditorPreparing (e) {
        if (e.dataField == "Note" && e.parentType === "dataRow") {
            const defaultValueChangeHandler = e.editorOptions.onValueChanged;
            e.editorName = "dxTextArea"; // Change the editor's type
            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);
            }
        }
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule,
        DxTextAreaModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        @editor-preparing="onEditorPreparing">
        <DxColumn
            data-field="Note"
            :editor-options="textAreaOptions"
        />
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList, {
    DxColumn
} from 'devextreme-vue/tree-list';
import 'devextreme-vue/text-area';

export default {
    components: {
        DxTreeList,
        DxColumn
    },
    data() {
        return {
            textAreaOptions: { height: 200 }
        }
    },
    methods: {
        onEditorPreparing(e) {
            if(e.dataField == "Note" && e.parentType === "dataRow") {
                const defaultValueChangeHandler = e.editorOptions.onValueChanged;
                e.editorName = "dxTextArea"; // Change the editor's type
                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
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList, {
    Column
} from 'devextreme-react/tree-list';
import 'devextreme-react/text-area';

class App extends React.Component {
    textAreaOptions = { height: 200 };
    onEditorPreparing(e) {
        if(e.dataField == "Note" && e.parentType === "dataRow") {
            const defaultValueChangeHandler = e.editorOptions.onValueChanged;
            e.editorName = "dxTextArea"; // Change the editor's type
            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.onEditorPreparing}>
                <Column
                    dataField="Note"
                    editorOptions={this.textAreaOptions}
                />
            </TreeList>
        );
    }
}
export default App;
ASP.NET MVC Controls
Razor C#
@(Html.DevExtreme().TreeList()
    // ...
    .Columns(cols => {
        // ...
        cols.Add().DataField("Note")
            .EditorOptions(new { height = 200 });
    })
    .OnEditorPreparing("treeList_editorPreparing")
)

<script type="text/javascript">
    function treeList_editorPreparing(e) {
        if (e.dataField == "Note" && e.parentType === "dataRow") {
            const defaultValueChangeHandler = e.editorOptions.onValueChanged;
            e.editorName = "dxTextArea"; // Change the editor's type
            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>

Implement the column's editCellTemplate for more extensive customization. In this template, you should specify your custom component's appearance and behavior in full. The following code uses the template to substitute the Switch UI component for a default editor. This configuration may be useful in batch editing mode.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        columns: [{
            dataField: "isChecked",
            editCellTemplate: function(cellElement, cellInfo) {
                $("<div />").dxSwitch({
                    width: 50,
                    switchedOnText: "YES",
                    switchedOffText: "NO",
                    value: cellInfo.value,
                    onValueChanged: function(e) {
                        cellInfo.setValue(e.value);
                    }
                }).appendTo(cellElement);
            }
        }],
        editing: {
            mode: "batch",
            allowUpdating: true
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxi-column
        dataField="isChecked"
        editCellTemplate="editCellTemplate">
    </dxi-column>
    <div *dxTemplate="let cellInfo of 'editCellTemplate'">
        <dx-switch
            [width]="50"
            switchedOnText="YES"
            switchedOffText="NO"
            [(value)]="cellInfo.value"
            (onValueChanged)="setEditedValue($event, cellInfo)">
        </dx-switch>
    </div>
    <dxo-editing mode="batch" [allowUpdating]="true"></dxo-editing>
</dx-tree-list>
import { DxTreeListModule, DxSwitchModule } from "devextreme-angular";
// ...
export class AppComponent {
    setEditedValue (valueChangedEventArg, cellInfo) {
        cellInfo.setValue(valueChangedEventArg.value);
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule,
        DxSwitchModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxColumn
            data-field="isChecked"
            edit-cell-template="switch"
        />
        <template #switch="{ data }">
            <DxSwitch
                :width="50"
                switched-on-text="YES"
                switched-off-text="NO"
                :value="data.value"
                @value-changed="setEditedValue($event, data)"
            />
        </template>
        <DxEditing
            mode="batch"
            :allow-updating="true"
        />
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList, {
    DxColumn,
    DxEditing
} from 'devextreme-vue/tree-list';

import DxSwitch from 'devextreme-vue/switch';

export default {
    components: {
        DxTreeList,
        DxColumn,
        DxEditing,
        DxSwitch
    },
    methods: {
        setEditedValue(valueChangedEventArg, cellInfo) {
            cellInfo.setValue(valueChangedEventArg.value);
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList, {
    Column,
    Editing
} from 'devextreme-react/tree-list';

import Switch from 'devextreme-react/switch';

class App extends React.Component {
    renderSwitch(cellInfo) {
        const setEditedValue = valueChangedEventArg => {
            cellInfo.setValue(valueChangedEventArg.value);
        }
        return (
            <Switch
                width={50}
                switchedOnText="YES"
                switchedOffText="NO"
                defaultValue={cellInfo.value}
                onValueChanged={setEditedValue}
            />
        )
    }

    render() {
        return (
            <TreeList ... >
                <Column
                    dataField="isChecked"
                    editCellRender={this.renderSwitch}
                />
                <Editing
                    mode="batch"
                    allowUpdating={true}
                />
            </TreeList>
        );
    }
}
export default App;
ASP.NET MVC Controls
Razor C#
@(Html.DevExtreme().TreeList()
    // ...
    .Columns(cols => {
        // ...
        cols.Add().DataField("isChecked")
            .EditCellTemplate(new TemplateName("edit-cells""));
    })
    .Editing(m => m.Mode(GridEditMode.Batch).AllowUpdating(true))
)

@using (Html.DevExtreme().NamedTemplate("edit-cells")) {
    @(Html.DevExtreme().Switch()
        .Width(50)
        .SwitchedOnText("YES")
        .SwitchedOffText("NO")
        .Value(new JS("value"))
        .OnValueChanged("function(e) { setValue(e.value) }")
    )
}

Editors are displayed in cells in the normal state too if you set the columns.showEditorAlways property to true.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        columns: [{
            dataField: "Hidden",
            dataType: "boolean",
            showEditorAlways: true
        }]
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxi-column
        dataField="Hidden"
        dataType="boolean"
        [showEditorAlways]="true">
    </dxi-column>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxColumn
            data-field="Hidden"
            data-type="boolean"
            :show-editor-always="true"
        />
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList, {
    DxColumn
} from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList,
        DxColumn
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList, {
    Column
} from 'devextreme-react/tree-list';

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Column
                    dataField="Hidden"
                    dataType="boolean"
                    showEditorAlways={true}
                />
            </TreeList>
        );
    }
}
export default App;
ASP.NET MVC Controls
Razor C#
@(Html.DevExtreme().TreeList()
    // ...
    .Columns(cols => {
        // ...
        cols.Add().DataField("Hidden")
            .DataType(GridColumnDataType.Boolean)
            .ShowEditorAlways(true);
    })
)
See Also

Data Validation

User input is validated against a set of validation rules. You can configure them in a column's validationRules array. Validation rules are attached to the editors and do not depend on the current edit mode.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        columns: [{
            dataField: "Full_Name",
            validationRules: [{ type: "required" }]
        }, {
            dataField: "Login",
            validationRules: [{ 
                type: "stringLength", 
                min: 3, 
                message: "Login should be longer than 3 symbols" 
            }]
        },
        // ...
        ]
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxi-column dataField="Full_Name">
        <dxi-validation-rule type="required"></dxi-validation-rule>
    </dxi-column>
    <dxi-column dataField="Login">
        <dxi-validation-rule
            type="stringLength"
            [min]="3"
            message="Login should be longer than 3 symbols" >
        </dxi-validation-rule>
    </dxi-column>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxColumn data-field="Full_Name">
            <DxRequiredRule />
        </DxColumn>
        <DxColumn data-field="Login">
            <DxStringLengthRule
                :min="3"
                message="Login should be at least 3 symbols long"
            />
        </DxColumn>
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList, {
    DxColumn,
    DxRequiredRule,
    DxStringLengthRule
} from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList,
        DxColumn,
        DxRequiredRule,
        DxStringLengthRule
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList, {
    Column,
    RequiredRule,
    StringLengthRule
} from 'devextreme-react/tree-list';

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Column dataField="Full_Name">
                    <RequiredRule />
                </Column>
                <Column dataField="Login">
                    <StringLengthRule
                        min={3}
                        message="Login should be at least 3 symbols long"
                    />
                </Column>
            </TreeList>
        );
    }
}
export default App;

The onRowValidating handler allows you to perform an action before a notification that a validation rule has been broken is displayed. For instance, you can perform additional checks in this handler and change the validation result by changing the handler parameter's isValid field.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        onRowValidating: function (e) {
            if (e.isValid && e.newData.Login === "Administrator") {
                e.isValid = false;
                e.errorText = "Your cannot log in as Administrator";
            }
        }
    });
});
Angular
TypeScript
HTML
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    barAdministratorLogin (e) {
        if (e.isValid && e.newData.Login === "Administrator") {
            e.isValid = false;
            e.errorText = "Your cannot log in as Administrator";
        }
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
<dx-tree-list ...
    (onRowValidating)="barAdministratorLogin($event)">
</dx-tree-list>
Vue
App.vue
<template>
    <DxTreeList ...
        @row-validating="denyAdminLogin">
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import DxTreeList from 'devextreme-vue/tree-list';

export default {
    components: {
        DxTreeList
    },
    methods: {
        denyAdminLogin(e) {
            if(e.isValid && e.newData.Login === "Administrator") {
                e.isValid = false;
                e.errorText = "Your cannot log in as Administrator";
            }
        }
    }
}
</script>
React
App.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import TreeList from 'devextreme-react/tree-list';

class App extends React.Component {
    denyAdminLogin(e) {
        if(e.isValid && e.newData.Login === "Administrator") {
            e.isValid = false;
            e.errorText = "Your cannot log in as Administrator";
        }
    }

    render() {
        return (
            <TreeList ...
                onRowValidating={this.denyAdminLogin}>
            </TreeList>
        );
    }
}
export default App;
See Also