React TreeList - Selection

User Interaction

The TreeList UI component supports single and multiple row selection. Use the selection.mode property to change the current mode.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        selection: {
            mode: "single" // or "multiple" | "none"
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxo-selection
        mode="single"> <!-- "multiple" | "none" -->
    </dxo-selection>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxSelection mode="single" /> <!-- "multiple" | "none" -->
    </DxTreeList>
</template>

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

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

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

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

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

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Selection mode="single" /> {/* "multiple" | "none" */}
            </TreeList>
        );
    }
}
export default App;

In the single mode, only one row can be selected at a time. In multiple mode, rows are supplied with check boxes for multiple selection. A check box in the first column's header allows a user to select all rows at once. Clicking this check box selects only those rows that meet the filtering conditions if a filter is applied.

DevExtreme HTML5 JavaScript jQuery Angular Knockout UI component TreeList Sorting

You can disable the latter feature by setting the selection.allowSelectAll property to false.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        selection: {
            mode: "multiple",
            allowSelectAll: false
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxo-selection
        mode="multiple"
        [allowSelectAll]="false">
    </dxo-selection>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxSelection
            mode="single"
            :allow-select-all="false"
        />
    </DxTreeList>
</template>

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

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

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

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

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

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Selection
                    mode="single"
                    allowSelectAll={false}
                />
            </TreeList>
        );
    }
}
export default App;

Selection is non-recursive by default, that is, only the clicked row is selected. Assign true to the selection.recursive property to make selection recursive. After that, a click on a row also selects nested rows, and a click on the column header's check box selects all rows disregarding applied filters.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        selection: {
            mode: "multiple",
            recursive: true
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ... >
    <dxo-selection
        mode="multiple"
        [recursive]="true">
    </dxo-selection>
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ... >
        <DxSelection
            mode="multiple"
            :recursive="true"
        />
    </DxTreeList>
</template>

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

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

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

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

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

class App extends React.Component {
    render() {
        return (
            <TreeList ... >
                <Selection
                    mode="multiple"
                    recursive={true}
                />
            </TreeList>
        );
    }
}
export default App;

Single Selection Demo Multiple Selection Demo

API

Initial and Runtime Selection

Use the selectedRowKeys property to select rows initially. With non-recursive selection, one key selects one row; with recursive - a row with its nested rows. Note that you should specify row keys beforehand. You can do it in the key field of the store that underlies the dataSource. Alternatively, you can set the UI component's keyExpr property. With hierarchical data, keys can be generated automatically if the key and keyExpr are not set.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        // ...
        dataSource: {
            store: {
                // ...
                key: "id"
            }
        },
        selectedRowKeys: [1, 5, 18]
    });
});
Angular
HTML
TypeScript
<dx-tree-list
    [dataSource]="treeListDataSource"
    [selectedRowKeys]="[1, 5, 18]">
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
import DataSource from "devextreme/data/data_source";
import "devextreme/data/array_store";
// or
// import "devextreme/data/odata/store";
// import "devextreme/data/custom_store";
// ...
export class AppComponent {
    treeListDataSource = new DataSource({
        store: {
            // ...
            key: "id"
        }
    });
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        :data-source="treeListDataSource"
        :selected-row-keys="[1, 5, 18]">
    </DxTreeList>
</template>

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

import DxTreeList from 'devextreme-vue/tree-list';
import DataSource from 'devextreme/data/data_source';
import 'devextreme/data/array_store';
// or
// import 'devextreme/data/odata/store';
// import 'devextreme/data/custom_store';

const treeListDataSource = new DataSource({
    store: {
        // ...
        key: 'id'
    }
});

export default {
    components: {
        DxTreeList
    },
    data() {
        return {
            treeListDataSource
        }
    }
}
</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 DataSource from 'devextreme/data/data_source';
import 'devextreme/data/array_store';
// or
// import 'devextreme/data/odata/store';
// import 'devextreme/data/custom_store';

const treeListDataSource = new DataSource({
    store: {
        // ...
        key: 'id'
    }
});

class App extends React.Component {
    selectedRowKeys = [1, 5, 18];

    render() {
        return (
            <TreeList ...
                dataSource={treeListDataSource}
                defaultSelectedRowKeys={this.selectedRowKeys}>
            </TreeList>
        );
    }
}
export default App;

You can select rows at runtime using the selectRows(keys, preserve) method. Note that the preserve argument, which tells the UI component whether to keep or clear the previous selection, is false by default. Before selecting a row, you can call the isRowSelected(key) method to check if this row is already selected. If you need to select all rows at once, call the selectAll() method.

jQuery
JavaScript
var selectSingleRow = function (treeListInstance, key, preserve) {
    if (!treeListInstance.isRowSelected(key)) {
        treeListInstance.selectRows([key], preserve);
    }
}
JavaScript
treeList.selectAll();
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;
    selectSingleRow (key, preserve) {
        if (!this.treeList.instance.isRowSelected(key)) {
            this.treeList.instance.selectRows([key], preserve);
        }
    }
    selectAllRows () {
        this.treeList.instance.selectAll();
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        v-model:selected-row-keys="selectedRowKeys"
        @content-ready="selectFirstRow">
    </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
    },
    data() {
        return {
            selectedRowKeys: []
        }
    },
    methods: {
        selectFirstRow(e) {
            const rowKey = e.component.getKeyByRowIndex(0);
            this.selectedRowKeys = [...this.selectedRowKeys, rowKey];

        }
    }
}
</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 {
    constructor(props) {
        super(props);
        this.state = {
            selectedRowKeys: []
        }
        this.selectFirstRow = this.selectFirstRow.bind(this);
        this.handleOptionChange = this.handleOptionChange.bind(this);
    }

    selectFirstRow(e) {
        const rowKey = e.component.getKeyByRowIndex(0);
        this.setState(prevState => ({
            selectedRowKeys: [...prevState.selectedRowKeys, rowKey]
        }));
    }

    handleOptionChange(e) {
        if(e.fullName === 'selectedRowKeys') {
            this.setState({
                selectedRowKeys: e.value
            });
        }
    }

    render() {
        return (
            <TreeList ...
                selectedRowKeys={this.state.selectedRowKeys}
                onContentReady={this.selectFirstRow}
                onOptionChanged={this.handleOptionChange}>
            </TreeList>
        );
    }
}
export default App;

Call the getSelectedRowKeys(mode) or getSelectedRowsData() method to get the selected rows' keys or data.

jQuery
JavaScript
var treeList = $("#treeListContainer").dxTreeList("instance");
var selectedKeys = treeList.getSelectedRowKeys("all"); // or "excludeRecursive" | "leavesOnly"
var selectedData = treeList.getSelectedRowsData();
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;
    getSelectedRowKeys () {
        return this.treeList.instance.getSelectedRowKeys("all"); // or "excludeRecursive" | "leavesOnly"
    }
    getSelectedRowsData () {
        return this.treeList.instance.getSelectedRowsData();
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        :ref="treeListRefKey">
    </DxTreeList>
</template>

<script>
import 'devextreme/dist/css/dx.common.css';
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: {
        getSelectedRowKeys() {
            return this.treeList.getSelectedRowKeys("all"); // or "excludeRecursive" | "leavesOnly"
        },
        getSelectedRowsData() {
            return this.treeList.getSelectedRowsData();
        }
    },
    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';

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

        this.getSelectedRowKeys = () => {
            return this.treeList.getSelectedRowKeys("all"); // or "excludeRecursive" | "leavesOnly"
        }
        this.getSelectedRowsData = () => {
            return this.treeList.getSelectedRowsData();
        }
    }

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

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

Clear Selection Settings

Call the deselectRows(keys) method to clear the selection of specific rows. With the non-recursive selection, one key deselects one row; with recursive - a row with its nested rows.

jQuery
JavaScript
$("#treeListContainer").dxTreeList("deselectRows", [1, 4, 10]);
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;
    deselectRows (keys) {
        this.treeList.instance.deselectRows(keys);
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        v-model:selected-row-keys="selectedRowKeys">
    </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
    },
    data() {
        return {
            selectedRowKeys: []
        }
    },
    methods: {
        deselectRows(keys) {
            let selectedRowKeys = this.selectedRowKeys;
            keys.forEach(function(item) {
                const index = selectedRowKeys.indexOf(item);
                if (index !== -1) {
                    const newRowKeys = [...this.selectedRowKeys];
                    newRowKeys.splice(index, 1);
                    this.selectedRowKeys = newRowKeys;
                }
            });
        }
    }
}
</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 {
    constructor(props) {
        super(props);
        this.state = {
            selectedRowKeys: []
        }
        this.deselectRows = this.deselectRows.bind(this);
        this.handleOptionChange = this.handleOptionChange.bind(this);
    }

    deselectRows(keys) {
        let selectedRowKeys = [...this.state.selectedRowKeys];
        keys.forEach(function(item) {
            const index = selectedRowKeys.indexOf(item);
            if (index !== -1) {
                selectedRowKeys.splice(index, 1);
            }
        });
        this.setState({
            selectedRowKeys: selectedRowKeys
        });
    }

    handleOptionChange(e) {
        if(e.fullName === 'selectedRowKeys') {
            this.setState({
                selectedRowKeys: e.value
            });
        }
    }

    render() {
        return (
            <TreeList ...
                selectedRowKeys={this.state.selectedRowKeys}
                onOptionChanged={this.handleOptionChange}>
            </TreeList>
        );
    }
}
export default App;

The deselectAll() method clears selection of all visible rows and can be used when you apply a filter and want to keep the selection of invisible rows that do not meet the filtering conditions. To clear the selection of all rows regardless of their visibility, call the clearSelection() method.

jQuery
JavaScript
var treeList = $("#treeListContainer").dxTreeList("instance");
treeList.deselectAll();
treeList.clearSelection();
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;
    deselectVisibleRows () {
        this.treeList.instance.deselectAll();
    }
    deselectAllRows () {
        this.treeList.instance.clearSelection();
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        ref="treeList"
        v-model:selected-row-keys="selectedRowKeys">
    </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
    },
    data() {
        return {
            selectedRowKeys: []
        }
    },
    methods: {
        deselectAllRows() {
            this.selectedRowKeys = [];
        },
        deselectVisibleRows() {
            this.$refs['treeList'].instance.deselectAll();
        }
    }
}
</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 {
    constructor(props) {
        super(props);
        this.state = {
            selectedRowKeys: []
        }
        this.treeListRef = React.createRef();
        this.deselectAllRows = this.deselectAllRows.bind(this);
        this.deselectVisibleRows = this.deselectVisibleRows.bind(this);
    }

    deselectAllRows() {
        this.setState({
            selectedRowKeys: []
        });
    }

    deselectVisibleRows() {
        this.treeListRef.current.instance.deselectAll();
    }

    handleOptionChange(e) {
        if(e.fullName === 'selectedRowKeys') {
            this.setState({
                selectedRowKeys: e.value
            });
        }
    }

    render() {
        return (
            <TreeList ...
                ref="treeListRef"
                selectedRowKeys={this.state.selectedRowKeys}
                onOptionChanged={this.handleOptionChange}>
            </TreeList>
        );
    }
}
export default App;
See Also

Events

The TreeList UI component raises the selectionChanged event when a row is selected or when the selection is cancelled. If the function that handles this event is going to remain unchanged, assign it to the onSelectionChanged property when you configure the UI component.

jQuery
JavaScript
$(function() {
    $("#treeListContainer").dxTreeList({
        onSelectionChanged: function(e) { // Handler of the "selectionChanged" event
            const currentSelectedRowKeys = e.currentSelectedRowKeys;
            const currentDeselectedRowKeys = e.currentDeselectedRowKeys;
            const allSelectedRowKeys = e.selectedRowKeys;
            const allSelectedRowsData = e.selectedRowsData;
            // ...
        }
    });
});
Angular
HTML
TypeScript
<dx-tree-list ...
    (onSelectionChanged)="onSelectionChanged($event)">
</dx-tree-list>
import { DxTreeListModule } from "devextreme-angular";
// ...
export class AppComponent {
    onSelectionChanged (e) { // Handler of the "selectionChanged" event
        const currentSelectedRowKeys = e.currentSelectedRowKeys;
        const currentDeselectedRowKeys = e.currentDeselectedRowKeys;
        const allSelectedRowKeys = e.selectedRowKeys;
        const allSelectedRowsData = e.selectedRowsData;
        // ...
    }
}
@NgModule({
    imports: [
        // ...
        DxTreeListModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxTreeList ...
        @selection-changed="onSelectionChanged">
    </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: {
        onSelectionChanged(e) {
            const currentSelectedRowKeys = e.currentSelectedRowKeys;
            const currentDeselectedRowKeys = e.currentDeselectedRowKeys;
            const allSelectedRowKeys = e.selectedRowKeys;
            const allSelectedRowsData = e.selectedRowsData;
            // ...
        }
    }
}
</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 {
    constructor(props) {
        super(props);

        this.onSelectionChanged = this.onSelectionChanged.bind(this);
    }

    onSelectionChanged(e) {
        const currentSelectedRowKeys = e.currentSelectedRowKeys;
        const currentDeselectedRowKeys = e.currentDeselectedRowKeys;
        const allSelectedRowKeys = e.selectedRowKeys;
        const allSelectedRowsData = e.selectedRowsData;
        // ...
    }

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

If you are going to change the event handler at runtime, or if you need to attach several handlers to the event, subscribe to it using the on(eventName, eventHandler) method.

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

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

$("#treeListContainer").dxTreeList("instance")
    .on("selectionChanged", selectionChangedEventHandler1)
    .on("selectionChanged", selectionChangedEventHandler2);
See Also