jQuery DataGrid - Master-Detail Interface

Watch Video

NOTE
You must specify the DataGrid's keyExpr or the Store's key property to ensure that the master-detail interface works properly.
See Also

User Interaction

The master-detail interface supplies a standard data row with an expandable section that contains detail data. In master-detail terms, the data row is called "master row" and the expandable section - "detail section".

DevExtreme HTML5/JavaScript DataGrid UI component Master Detail Interface

The master-detail interface becomes available after you specify the detail sections' contents using the masterDetail.template property. You can expand and collapse detail sections programmatically or enable a user to do it by setting the masterDetail.enabled property to true. Set the masterDetail.autoExpandAll property to true to expand these sections by default.

jQuery
JavaScript
$(function() {
    $("#dataGridContainer").dxDataGrid({
        // ...
        masterDetail: {
            enabled: true,
            autoExpandAll: true,
            template: function (container, info) {
                сonst currentEmployeeData = info.data;
                container.append(
                    $('<div class="employeeInfo">
                        <img class="employeePhoto" src="' + currentEmployeeData.Picture + '" />
                        <p class="employeeNotes">' + currentEmployeeData.Notes + '</p>
                    </div>')
                );
            } 
        }
    });
});
Angular
HTML
TypeScript
<dx-data-grid ... >
    <dxo-master-detail
        [enabled]="true"
        [autoExpandAll]="true"
        [template]="'detail'">
    </dxo-master-detail>
    <div *dxTemplate="let employee of 'detail'">
        <div class="employeeInfo">
            <img class="employeePhoto" [src]="employee.data.Picture" />
            <p class="employeeNotes">{{employee.data.Notes}}</p>
        </div>
    </div>
</dx-data-grid>
import { DxDataGridModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxMasterDetail
            :enabled="true"
            :auto-expand-all="true"
            template="detail"
        />
        <template #detail="{ data }">
            <div class="employeeInfo">
                <img class="employeePhoto" :src="data.Picture" />
                <p class="employeeNotes">{{ data.Notes }}</p>
            </div>
        </template>
    </DxDataGrid>
</template>

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

import DxDataGrid, {
    DxMasterDetail
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxMasterDetail
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.light.css';

import DataGrid, {
    MasterDetail
} from 'devextreme-react/data-grid';

const DetailSection = ({ data }) => {
    return (
        <div class="employeeInfo">
            <img class="employeePhoto" src={data.Picture} />
            <p class="employeeNotes">{data.Notes}</p>
        </div>
    );
};

export default function App() {
    return (
        <DataGrid ... >
            <MasterDetail
                enabled={true}
                autoExpandAll={true}
                render={DetailSection}
            />
        </DataGrid>
    );
}

Once loaded, a detail section's content remains cached until a user switches to another page in the DataGrid or reloads the web page.

View Demo

API

Pass -1 to the expandAll(groupIndex) or collapseAll(groupIndex) method to expand or collapse all master rows at once.

jQuery
JavaScript
const dataGrid = $("#dataGridContainer").dxDataGrid("instance");
dataGrid.expandAll(-1);
dataGrid.collapseAll(-1);
Angular
TypeScript
import { ..., ViewChild } from "@angular/core";
import { DxDataGridModule, DxDataGridComponent } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
    // Prior to Angular 8
    // @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
    expandAllMasterRows () {
        this.dataGrid.instance.expandAll(-1);
    }
    collapseAllMasterRows () {
        this.dataGrid.instance.collapseAll(-1);
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxDataGrid ...
        :ref="dataGridRefKey">
        <!-- ... -->
    </DxDataGrid>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';
import DxDataGrid, { ... } from 'devextreme-vue/data-grid';

const dataGridRefKey = "my-data-grid";

export default {
    components: {
        DxDataGrid,
        // ...
    },
    data: function() {
        return {
            dataGridRefKey
        };
    },
    methods: {
        expandAllMasterRows() {
            this.dataGrid.expandAll(-1);
        },
        collapseAllMasterRows() {
            this.dataGrid.collapseAll(-1);
        }
    },
    computed: {
        dataGrid: function() {
            return this.$refs[dataGridRefKey].instance;
        }
    }
}
</script>
React
App.js
import React, { useRef, useCallback } from 'react';
import 'devextreme/dist/css/dx.light.css';

import DataGrid, { ... } from 'devextreme-react/data-grid';

export default function App() {
    const dataGrid = useRef(null);
    const expandAllMasterRows = useCallback(() => {
        dataGrid.current.instance.expandAll(-1);
    }, []);
    const collapseAllMasterRows = useCallback(() => {
        dataGrid.current.instance.collapseAll(-1);
    }, []);

    return (
        <DataGrid ...
            ref={dataGrid}>
            {/* ... */}
        </DataGrid>
    );
}

The expandRow(key) and collapseRow(key) methods expand and collapse an individual master row. You can check a row's current state by calling the isRowExpanded(key) method.

jQuery
JavaScript
function toggleMasterRow (rowKey) {
    const dataGrid = $("#dataGridContainer").dxDataGrid("instance");
    if (dataGrid.isRowExpanded(rowKey)) {
        dataGrid.collapseRow(rowKey);
    } else {
        dataGrid.expandRow(rowKey);
    }
}
Angular
TypeScript
import { ..., ViewChild } from "@angular/core";
import { DxDataGridModule, DxDataGridComponent } from "devextreme-angular";
// ...
export class AppComponent {
    @ViewChild(DxDataGridComponent, { static: false }) dataGrid: DxDataGridComponent;
    // Prior to Angular 8
    // @ViewChild(DxDataGridComponent) dataGrid: DxDataGridComponent;
    toggleMasterRow (rowKey) {
        if (this.dataGrid.instance.isRowExpanded(rowKey)) {
            this.dataGrid.instance.collapseRow(rowKey);
        } else {
            this.dataGrid.instance.expandRow(rowKey);
        }
    }
}
@NgModule({
    imports: [
        // ...
        DxDataGridModule
    ],
    // ...
})
Vue
App.vue
<template>
    <DxDataGrid ...
        :ref="dataGridRefKey">
        <!-- ... -->
    </DxDataGrid>
</template>

<script>
import 'devextreme/dist/css/dx.light.css';
import DxDataGrid, { ... } from 'devextreme-vue/data-grid';

const dataGridRefKey = "my-data-grid";

export default {
    components: {
        DxDataGrid,
        // ...
    },
    data: function() {
        return {
            dataGridRefKey
        };
    },
    methods: {
        toggleMasterRow(rowKey) {
            if (this.dataGrid.isRowExpanded(rowKey)) {
                this.dataGrid.collapseRow(rowKey);
            } else {
                this.dataGrid.expandRow(rowKey);
            }
        }
    },
    computed: {
        dataGrid: function() {
            return this.$refs[dataGridRefKey].instance;
        }
    }
}
</script>
React
App.js
import React, { useRef, useCallback } from 'react';
import 'devextreme/dist/css/dx.light.css';

import DataGrid, { ... } from 'devextreme-react/data-grid';

export default function App() {
    const dataGrid = useRef(null);
    const toggleMasterRow = useCallback((rowKey) => {
        if (dataGrid.current.instance.isRowExpanded(rowKey)) {
            dataGrid.current.instance.collapseRow(rowKey);
        } else {
            dataGrid.current.instance.expandRow(rowKey);
        }
    }, []);

    return (
        <DataGrid ...
            ref={dataGrid}>
            {/* ... */}
        </DataGrid>
    );
}

View Demo

Events

Events raised for a master row when a user expands or collapses it are identical to the events raised for expanding or collapsing a group. See this topic for details.