DevExtreme v24.1 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

Advanced Master-Detail View

This demo illustrates an advanced master-detail view in the DataGrid component. Master rows represent suppliers. Detail sections contain TabPanel components with two tabs: Orders and Address. In the Orders tab, you can choose a supplier's product from the SelectBox, and the DataGrid under it will show orders placed on this product. The Address tab displays the supplier's address.

Backend API
const url = 'https://js.devexpress.com/Demos/Mvc/api/DataGridAdvancedMasterDetailView'; $(() => { $('#gridContainer').dxDataGrid({ showBorders: true, dataSource: DevExpress.data.AspNet.createStore({ key: 'SupplierID', loadUrl: `${url}/GetSuppliers`, }), paging: { pageSize: 15, }, remoteOperations: true, columns: [ 'ContactName', 'ContactTitle', 'CompanyName', 'City', 'Country', ], masterDetail: { enabled: true, template: masterDetailTemplate, }, }); }); function masterDetailTemplate(_, masterDetailOptions) { return $('<div>').dxTabPanel({ items: [{ title: 'Orders', template: createOrdersTabTemplate(masterDetailOptions.data), }, { title: 'Address', template: createAddressTabTemplate(masterDetailOptions.data), }], }); } function createOrdersTabTemplate(masterDetailData) { return function () { let orderHistoryDataGrid; function onProductChanged(productID) { orderHistoryDataGrid.option('dataSource', createOrderHistoryStore(productID)); } function onDataGridInitialized(e) { orderHistoryDataGrid = e.component; } return $('<div>').addClass('form-container').dxForm({ labelLocation: 'top', items: [{ label: { text: 'Product' }, template: createProductSelectBoxTemplate(masterDetailData, onProductChanged), }, { label: { text: 'Order History' }, template: createOrderHistoryTemplate(onDataGridInitialized), }], }); }; } function createProductSelectBoxTemplate(masterDetailData, onProductChanged) { return function () { return $('<div>').dxSelectBox({ inputAttr: { 'aria-label': 'Product' }, dataSource: DevExpress.data.AspNet.createStore({ key: 'ProductID', loadParams: { SupplierID: masterDetailData.SupplierID }, loadUrl: `${url}/GetProductsBySupplier`, }), valueExpr: 'ProductID', displayExpr: 'ProductName', deferRendering: false, onContentReady(e) { const firstItem = e.component.option('items[0]'); if (firstItem) { e.component.option('value', firstItem.ProductID); } }, onValueChanged(e) { onProductChanged(e.value); }, }); }; } function createOrderHistoryTemplate(onDataGridInitialized) { return function () { return $('<div>').dxDataGrid({ onInitialized: onDataGridInitialized, paging: { pageSize: 5, }, showBorders: true, columns: [ 'OrderID', { dataField: 'OrderDate', dataType: 'date', }, 'ShipCountry', 'ShipCity', { dataField: 'UnitPrice', format: 'currency', }, 'Quantity', { dataField: 'Discount', format: 'percent', }, ], summary: { totalItems: [{ column: 'UnitPrice', summaryType: 'sum', valueFormat: { format: 'currency', precision: 2, }, }, { column: 'Quantity', summaryType: 'count', }], }, }); }; } function createAddressTabTemplate(data) { return function () { return $('<div>').addClass('address-form form-container').dxForm({ formData: data, colCount: 2, customizeItem(item) { item.template = formItemTemplate; }, items: ['Address', 'City', 'Region', 'PostalCode', 'Country', 'Phone'], }); }; } function formItemTemplate(item) { return $('<span>').text(item.editorOptions.value); } function createOrderHistoryStore(productID) { return DevExpress.data.AspNet.createStore({ key: 'OrderID', loadParams: { ProductID: productID }, loadUrl: `${url}/GetOrdersByProduct`, }); }
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" /> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <script>window.jQuery || document.write(decodeURIComponent('%3Cscript src="js/jquery.min.js"%3E%3C/script%3E'))</script> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.1.3/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="js/dx.all.js"></script> <script src="https://unpkg.com/devextreme-aspnet-data@4.0.0/js/dx.aspnet.data.js"></script> <script src="index.js"></script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="gridContainer"></div> </div> </body> </html>
#gridContainer { height: 620px; } .dx-datagrid-rowsview .dx-master-detail-row:not(.dx-datagrid-edit-form) > .dx-datagrid-group-space, .dx-datagrid-rowsview .dx-master-detail-row:not(.dx-datagrid-edit-form) .dx-master-detail-cell { background-color: transparent; } .form-container { padding: 20px; } .address-form label { font-weight: bold; }