Your search did not match any results.
Data Grid

Advanced Master-Detail View

This demo illustrates an advanced master-detail view in the DataGrid widget. Master rows represent suppliers. Detail sections contain TabPanel widgets 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.

Copy to CodePen
Apply
Reset
var DemoApp = angular.module('DemoApp', ['dx']); const url = "https://js.devexpress.com/Demos/Mvc/api/DataGridAdvancedMasterDetailView"; DemoApp.controller('DemoController', function DemoController($scope) { $scope.gridOptions = { 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: "masterDetail" } }; $scope.getTabPanelOptions = function(masterDetailData) { return { items: [{ title: "Orders", template: "ordersTab" }, { title: "Address", template: "addressTab", }] }; }; $scope.getAddressTabOptions = function(data) { return { formData: data, colCount: 2, customizeItem: function(item) { item.template = "formItemTemplate"; }, items: ["Address", "City", "Region", "PostalCode", "Country", "Phone"] }; } }); DemoApp.controller("OrdersTabController", function OrdersTabController($scope) { function createOrderHistoryStore(productID) { return DevExpress.data.AspNet.createStore({ key: "OrderID", loadParams: { ProductID: productID }, loadUrl: url + "/GetOrdersByProduct" }); } $scope.getOrdersTabOptions = function(masterDetailData) { return { labelLocation: "top", items: [{ label: { text: "Product" }, template: "productSelectBox" }, { label: { text: "Order History" }, template: "orderHistory" }] }; }; $scope.getSelectBoxOptions = function(masterDetailData) { return { dataSource: DevExpress.data.AspNet.createStore({ key: "ProductID", loadParams: { SupplierID: masterDetailData.SupplierID }, loadUrl: url + "/GetProductsBySupplier" }), valueExpr: "ProductID", displayExpr: "ProductName", deferRendering: false, onContentReady: function(e) { let firstItem = e.component.option("items[0]"); if(firstItem) { e.component.option("value", firstItem.ProductID); } }, onValueChanged: function(e) { $scope.dataSource = createOrderHistoryStore(e.value); } }; }; $scope.orderHistoryDataGridOptions = { bindingOptions: { dataSource: { deep: false, dataPath: "dataSource" } }, 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" }] } }; });
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" > <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=1.0" /> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.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/19.2.4/css/dx.common.css" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/19.2.4/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular.min.js"></script> <script>window.angular || document.write(decodeURIComponent('%3Cscript src="js/angular.min.js"%3E%3C\/script%3E'))</script> <script src="https://cdn3.devexpress.com/jslib/19.2.4/js/dx.all.js"></script> <script src="https://unpkg.com/devextreme-aspnet-data@2.5.1/js/dx.aspnet.data.js"></script> <script src="index.js"></script> </head> <body class="dx-viewport"> <div class="demo-container" ng-app="DemoApp" ng-controller="DemoController"> <div dx-data-grid="gridOptions" dx-item-alias="masterDetailItem" id="gridContainer"> <div data-options="dxTemplate: {name: 'masterDetail'}"> <div dx-tab-panel="getTabPanelOptions(masterDetailItem.data)"> <div data-options="dxTemplate: {name: 'ordersTab'}" > <div ng-controller="OrdersTabController"> <div dx-form="getOrdersTabOptions(masterDetailItem.data)" class="form-container"> <div data-options="dxTemplate: {name: 'productSelectBox'}"> <div dx-select-box="getSelectBoxOptions(masterDetailItem.data)"></div> </div> <div data-options="dxTemplate: {name: 'orderHistory'}"> <div dx-data-grid="orderHistoryDataGridOptions"></div> </div> </div> </div> </div> <div data-options="dxTemplate: {name: 'addressTab'}" > <div dx-form="getAddressTabOptions(masterDetailItem.data)" dx-item-alias="formItem" class="address-form form-container"> <div data-options="dxTemplate: {name: 'formItemTemplate'}"> <span>{{formItem.editorOptions.value}}</span> </div> </div> </div> </div> </div> </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; }