Row Details

Sometimes rows are bound to data objects that contain more information than what would fit easily on a regular grid.

In these scenarios, you may want to use the FlexGridDetailProvider class that is included with the wijmo.grid.detail module.

FlexGridDetailProvider extends the FlexGrid class by adding collapse/expand buttons to row headers, and a createDetailCell method that can be used to provide additional details about an item. The detail information is shown in a 'detail row' added to the grid when the details are expanded, and removed when they are collapsed.

HTML in Row Details

This grid shows product categories on each row. Expanding the rows shows an HTML element with information about the products in that category.

Grids in Row Details

You can add anything you want to the detail rows, including other grids. This example shows the same categories, but the detail row uses another grid to show the products.

// This file locates: "Scripts/Lesson/C1FlexGrid/RowsDetails.js".
c1.documentReady(function () {
    // html detail provider
    var htmlDetail = wijmo.Control.getControl('#htmlDetail');
    // html detail provider
    var dpHtml = c1.getExtender(htmlDetail, 'htmlDetailRow');
    // use animation when showing details
    dpHtml.isAnimated = true;
    // create detail cells for a given row
    dpHtml.createDetailCell = function (row) {

        // build detail content for the current category
        var cat = row.dataItem;
        var prods = getProducts(cat.CategoryID);
        var html = 'ID: <b>' + cat.CategoryID + '</b><br/>';
        html += 'Name: <b>' + cat.CategoryName + '</b><br/>';
        html += 'Description: <b>' + cat.Description + '</b><br/>';
        html += 'Products: <b>' + prods.length + ' items</b><br/>';
        html += '<ol>';
        prods.forEach(function (product) {
            html += '<li>' + product.ProductName + '</li>';
        });
        html += '</ol>';

        // create and return detail cell
        var cell = document.createElement('div');
        cell.innerHTML = html;
        return cell;
    }

    // grid with grid detail
    var gridDetail = wijmo.Control.getControl('#gridDetail');
    // grid detail provider
    var dpGrid = c1.getExtender(gridDetail, 'gridDetailRow');
    // use animation when showing details
    dpGrid.isAnimated = true;
    // limit height of detail rows
    dpGrid.maxHeight = 150;
    // create detail cells for a given row
    dpGrid.createDetailCell = function (row) {
        var cell = document.createElement('div');
        var detailGrid = new wijmo.grid.FlexGrid(cell, {
            headersVisibility: wijmo.grid.HeadersVisibility.Column,
            autoGenerateColumns: false,
            itemsSource: getProducts(row.dataItem.CategoryID),
            columns: [
                { header: 'ID', binding: 'ProductID' },
              { header: 'Name', binding: 'ProductName' },
              { header: 'Qty/Unit', binding: 'QuantityPerUnit' },
              { header: 'Unit Price', binding: 'UnitPrice' },
              { header: 'Discontinued', binding: 'Discontinued' }
            ]
        });
        return cell;
    }

    var categories = [], products = [];
    var categoriesIsDone = false, productsIsDone = false;

    function validate() {
        if (categoriesIsDone && productsIsDone) {
            htmlDetail.itemsSource = categories;
            gridDetail.itemsSource = categories;
        }
    }

    // get products for a given category
    function getProducts(categoryID) {
        var arr = [];
        products.forEach(function (product) {
            if (product.CategoryID == categoryID) {
                arr.push(product);
            }
        });
        return arr;
    }

    // get data from OData service
    var nwindService = 'https://services.odata.org/Northwind/Northwind.svc/';
    function getOdata(url, fill, finish) {
        wijmo.httpRequest(nwindService + url, {
            success: function (xhr) {
                var data = JSON.parse(xhr.responseText);
                fill(data.value);

                var nextLink = data['odata.nextLink'];
                if (nextLink == null) {
                    finish();
                } else {
                    getOdata(nextLink + '&$format=json', fill, finish);
                }
            }
        });
    }

    var categoriesUrl = 'Categories?$format=json&$inlinecount=allpages&$select=CategoryID,CategoryName,Description';
    getOdata(categoriesUrl,
        function (value) {
            categories = categories.concat(value);
        },
        function () {
            categoriesIsDone = true;
            validate();
        });

    var productsUrl = 'Products?$format=json&$inlinecount=allpages';
    getOdata(productsUrl,
        function (value) {
            products = products.concat(value);
        },
        function () {
            productsIsDone = true;
            validate();
        });
});

using System.Web.Mvc;

namespace LearnMvcClient.Controllers
{
    public partial class C1FlexGridController : Controller
    {
        // GET: RowsDetails
        public ActionResult RowsDetails()
        {
            return View(Models.FlexGridData.GetSales());
        }
    }
}
@model IEnumerable<FlexGridData.Sale>

<h1>
    @Html.Raw(Resources.C1FlexGrid.RowsDetails_Title)
</h1>
<p>
    @Html.Raw(Resources.C1FlexGrid.RowsDetails_Text1)
</p>
<p>
    @Html.Raw(Resources.C1FlexGrid.RowsDetails_Text2)
</p>
<p>
    @Html.Raw(Resources.C1FlexGrid.RowsDetails_Text3)
</p>

<h3>
    @Html.Raw(Resources.C1FlexGrid.RowsDetails_Title1)
</h3>
<p>
    @Html.Raw(Resources.C1FlexGrid.RowsDetails_Text4)
</p>
@(Html.C1().FlexGrid().Id("htmlDetail").Height(250)
    .AutoGenerateColumns(false)
    .Columns(cs=>
    {
        cs.Add().Binding("CategoryName").Header("Category Name").Width("*");
        cs.Add().Binding("Description").Header("Description").Width("2*");
    })
    .ShowDetailRow(d => d.Id("htmlDetailRow"))
)

<h3>
    @Html.Raw(Resources.C1FlexGrid.RowsDetails_Title2)
</h3>
<p>
    @Html.Raw(Resources.C1FlexGrid.RowsDetails_Text5)
</p>
@(Html.C1().FlexGrid().Id("gridDetail").Height(250)
    .AutoGenerateColumns(false)
    .Columns(cs=>
    {
        cs.Add().Binding("CategoryName").Header("Category Name").Width("*");
        cs.Add().Binding("Description").Header("Description").Width("2*");
    })
    .ShowDetailRow(d => d.Id("gridDetailRow"))
)