Data Grids / Data Management ▸ Advanced Master-Detail View

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

@(Html.DevExtreme().DataGrid<DevExtreme.MVC.Demos.Models.Northwind.Supplier>()
    .ID("gridContainer")
    .DataSource(d => d.WebApi().Controller("DataGridAdvancedMasterDetailView").LoadAction("GetSuppliers").Key("SupplierID"))
    .Paging(p => p.PageSize(15))
    .Pager(p => p.Visible(true))
    .ShowBorders(true)
    .Columns(columns => {
        columns.AddFor(m => m.ContactName);

        columns.AddFor(m => m.ContactTitle);

        columns.AddFor(m => m.CompanyName);

        columns.AddFor(m => m.City);

        columns.AddFor(m => m.Country);
    })
    .MasterDetail(m => m
        .Enabled(true)
        .Template(new TemplateName("gridContainer-details"))
    )
)

@using(Html.DevExtreme().NamedTemplate("gridContainer-details")) {
    @(Html.DevExtreme().TabPanel()
        .Items(items => {
            items.Add()
                .Title("Orders")
                .Template(new TemplateName("gridContainer-details-tab1Template"))
                .Option("tabExtras", new { supplierID = new JS("data.SupplierID") });

            items.Add()
                .Title("Address")
                .Template(new TemplateName("gridContainer-details-tab2Template"))
                .Option("tabExtras", new JS("data"));
        })
    )
}

@using(Html.DevExtreme().NamedTemplate("gridContainer-details-tab1Template")) {
    @(Html.DevExtreme().Form()
        .ElementAttr("class", "form-container")
        .FormData(new JS("tabExtras"))
        .LabelLocation(FormLabelLocation.Top)
        .Items(items => {
            items.AddSimple()
                .Label(l => l.Text("Product"))
                .Editor(e => e.SelectBox()
                    .InputAttr("aria-label", "Product")
                    .DataSource(d => d.WebApi()
                        .Controller("DataGridAdvancedMasterDetailView")
                        .LoadAction("GetProductsBySupplier")
                        .LoadParams(new { supplierID = new JS("tabExtras.supplierID") })
                        .Key("ProductID")
                    )
                    .ValueExpr("ProductID")
                    .DisplayExpr("ProductName")
                    .DeferRendering(false)
                    .OnContentReady(@<text>
                        function(e) {
                            var firstItem = e.component.option("items[0]");
                            if(firstItem) {
                                e.component.option("value", firstItem.ProductID);
                            }
                        }
                    </text>)
                    .OnSelectionChanged(@<text>
                        function(e) {
                            tabExtras.productID = e.selectedItem.ProductID;
                            $("#gridContainer-orderHistoryGrid-" + tabExtras.supplierID).dxDataGrid("instance").refresh();
                        }
                    </text>)
                );

            items.AddSimple()
                .Label(l => l.Text("Order History"))
                .Template(new TemplateName("gridContainer-details-tab1-gridTemplate"));
        })
    )
}

@using(Html.DevExtreme().NamedTemplate("gridContainer-details-tab1-gridTemplate")) {
    @(Html.DevExtreme().DataGrid()
        .ID(new JS("'gridContainer-orderHistoryGrid-' + component.option('formData').supplierID"))
        .ShowBorders(true)
        .DataSource(d => d.WebApi()
            .Controller("DataGridAdvancedMasterDetailView")
            .LoadAction("GetOrdersByProduct")
            .LoadParams(new {
                productID = new JS("function() { return component.option('formData').productID }")
            })
        )
        .Paging(p => p.PageSize(5))
        .Columns(columns => {
            columns.Add().DataField("OrderID");
            columns.Add().DataField("OrderDate").DataType(GridColumnDataType.Date);
            columns.Add().DataField("ShipCountry");
            columns.Add().DataField("ShipCity");
            columns.Add().DataField("UnitPrice").Format(Format.Currency);
            columns.Add().DataField("Quantity");
            columns.Add().DataField("Discount").Format(Format.Percent);
        })
        .Summary(s => s
            .TotalItems(totalItems => {
                totalItems.Add()
                    .Column("UnitPrice")
                    .SummaryType(SummaryType.Sum)
                    .ValueFormat(f => f
                        .Currency("USD")
                        .Precision(2)
                    );

                totalItems.Add()
                    .Column("Quantity")
                    .SummaryType(SummaryType.Count);
            })
        )
    )
}

@using(Html.DevExtreme().NamedTemplate("gridContainer-details-tab2Template")) {
    var formItemTemplate = "<%- editorOptions.value %>";

    @(Html.DevExtreme().Form()
        .ElementAttr("class", "address-form form-container")
        .FormData(new JS("tabExtras"))
        .ColCount(2)
        .Items(items => {
            items.AddSimple().DataField("Address").Template(formItemTemplate);
            items.AddSimple().DataField("City").Template(formItemTemplate);
            items.AddSimple().DataField("Region").Template(formItemTemplate);
            items.AddSimple().DataField("PostalCode").Template(formItemTemplate);
            items.AddSimple().DataField("Country").Template(formItemTemplate);
            items.AddSimple().DataField("Phone").Template(formItemTemplate);
        })
    )
}
using DevExtreme.MVC.Demos.Models;
using DevExtreme.MVC.Demos.Models.DataGrid;
using DevExtreme.MVC.Demos.Models.SampleData;
using System;
using System.Linq;
using System.Web.Mvc;

namespace DevExtreme.MVC.Demos.Controllers {
    public class DataGridController : Controller {

        public ActionResult AdvancedMasterDetailView() {
            return View();
        }

    }
}
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using DevExtreme.MVC.Demos.Models.Northwind;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace DevExtreme.MVC.Demos.Controllers.ApiControllers {
    public class DataGridAdvancedMasterDetailViewController : ApiController {
        NorthwindContext _nwinds = new NorthwindContext();

        [HttpGet]
        public object GetSuppliers(DataSourceLoadOptions options) {
            return DataSourceLoader.Load(_nwinds.Suppliers, options);
        }

        [HttpGet]
        public object GetProductsBySupplier(int supplierID, DataSourceLoadOptions options) {
            return DataSourceLoader.Load(_nwinds.Products.Where(p => p.SupplierID == supplierID), options);
        }

        [HttpGet]
        public object GetOrdersByProduct(int productID, DataSourceLoadOptions options) {
            var query = from i in _nwinds.Order_Details
                        where i.ProductID == productID
                        join j in _nwinds.Orders on i.OrderID equals j.OrderID
                        select new {
                            i.OrderID,
                            j.OrderDate,
                            j.ShipCountry,
                            j.ShipCity,
                            i.UnitPrice,
                            i.Quantity,
                            i.Discount
                        };

            return DataSourceLoader.Load(query, options);
        }
    }
}
#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;
}