Skip to main content Skip to footer

Transform a FlexGrid Row into a Customizable DetailRow

In addition to the FinancialChart and FlexSheet, the Wijmo5 2015 release contains a new extension for the FlexGrid: DetailRow. The DetailRow extension provides the developer with a template for an expandable, and highly customizable, row, and provides your end users with another layer of information and interactivity. Using a directive or calling the classes directly in your JavaScript transforms any row in your FlexGrid into a DetailRow, complete with customizable expand/collapse buttons. This blog walks through creating a FlexGrid and transforming it using the DetailRow extensions to display row details. This guide will use the Northwind database which schema is detailed below:

Getting Started: Add Angular JS, Wijmo 5 and Wijmo 5's AngularJS Directives

  1. In order to use the FlexGrid, you need to add the necessary references to our application. These include the AngularJS, Wijmo5, and Wijmo5’s AngularJS directives. In this instance, Wijmo5 does not have any third party dependencies other than AngularJS.
  2. Include the Wijmo5 directive in the app module declaration:
var app = angular.module('app', ['wj']);

  1. Add the control host to your markup, to provide the control’s items source:
<wj-flex-grid
allow-dragging="Both"
items-source="categories">
</wj-flex-grid>

  1. Add a controller to provide some data and logic. Note: for this demo you're using http and interval, so don’t forget to pass those.
app.controller('appCtrl', function appCtrl($scope,$http,$interval) {
});

  1. Add the app name and the app control to your body tag:
<body ng-app="app" ng-controller="appCtrl">

  1. Add the DetailRow extension to the application:
<script src="scripts/wijmo.grid.detail.min.js"></script>

Now that you have all the necessary references and configured your AngularJS application, you’ll add FlexGrid markup in between your body. For the purpose of this sample, you’ll connect to the Northwind data service. If you look at my plnkr or sample code, you'll see the logic you need to connect to that service. For those of us who have used Northwind before, the bindings should seem familiar. For those who haven’t, I encourage you to review the diagram above since you're dealing with joined hierarchical data.

Here, you'll create a new FlexGrid and create two columns. Bind each column to the name of the category and the description.

<wj-flex-grid items-source="categories">
<wj-flex-grid-column header="Name" binding="CategoryName">
</wj-flex-grid-column>
<wj-flex-grid-column header="Description" binding="Description" width="*">
</wj-flex-grid-column>
</wj-flex-grid>

Add a Simple Detail Row

Now, add the DetailRow. You need to add the markup inside your wij-flex-grid tag. Here you are binding the height to a static number, and the detail visibility mode to an AngularJS property in your app.js file:

$scope.detailMode = wijmo.grid.detail.DetailVisibilityMode.ExpandMulti;

And in your markup:

<wj-flex-grid-detail max-height="250" detail-visibility-mode="{{detailMode}}">
   ID: <b>{{$item.CategoryID}}</b><br />
   Name: <b>{{$item.CategoryName}}</b><br />
   Description: <b>{{$item.Description}}</b><br />    
</wj-flex-grid-detail>

You can see the plain old HTML code inside your DetailRow and some AngularJS expressions. If you run the sample, you should see this:

In addition to using the detail row directive, you can use the FlexGridDetailProvider class directly in your JavaScript, which will be introduced below.

View Plnkr for Simple Getting Started Sample >>

Loading DetailRow using a Directive with another Template

For this example, you'll start off with the markup from the index.html file from the attached sample.

<wj-flex-grid items-source="categories">
   <wj-flex-grid-column header="Name" binding="CategoryName">
   </wj-flex-grid-column>
   <wj-flex-grid-column header="Description" binding="Description" width="*">
   </wj-flex-grid-column>
</wj-flex-grid>

Now, add the directive for the DetailRow:

<wj-flex-grid-detail detail-visibility-mode="ExpandSingle">
//template goes here
</wj-flex-grid-detail>

As you can see in the commented section, the template will go inside the directive. This is very similar to the first example using the markup, so take that and add a repeater to it. Here's the template:

ID: <b>{{$item.CategoryID}}</b><br />
Name: <b>{{$item.CategoryName}}</b><br />
Description: <b>{{$item.Description}}</b><br />
<ol>
  <li ng-repeat="p in getProducts($item.CategoryID).items">{{p.ProductName}}</li>
</ol>

The result should look something like the following:

In the next section you’ll add a FlexGrid to the DetailRow.

View Plnkr for Sample using Templates via Directives >>

Embed FlexGrid into a Row Using Directives

If you’d like, you can embed another instance of FlexGrid into the DetailRow. In this case, you’ll want to bind the second instance to a different dataset. This will require some configurations in your app.js file. To begin, you need to be able to select the details of the unique row that the user is requesting. Use a getProducts() function to get all of the products for that category, and return them to a CollectionView for the new FlexGrid to consume.

$scope.getProducts = function (categoryID) {
        var view = products[categoryID];
        if (!view) {
            view = new wijmo.collections.CollectionView($scope.products.sourceCollection);
            view.filter = function (item) {
                return item.CategoryID == categoryID;
            }
            products[categoryID] = view;
        }
        return view;
    }

Adding the FlexGrid itself to the DetailRow is pretty straightforward:

<wj-flex-grid items-source="getProducts($item.CategoryID)" headers visibility="Column">
</wj-flex-grid>

Run your application, and you should see:

View Plnkr for Embedding FlexGrid via Directives Sample >>

Embed FlexGrid into a Row using Class

In this demonstration, you'll specify a createDetailCell() function. This function creates your child HTML elements for your detail row. You'll use the same data service and start out with the same FlexGrid, adding an initialized function:

<wj-flex-grid items-source="categories" initialized="initDetailProvider(s,e)">
   <wj-flex-grid-column header="Name" binding="CategoryName">
   </wj-flex-grid-column>
   <wj-flex-grid-column header="Description" binding="Description" width="*">
     </wj-flex-grid-column>
</wj-flex-grid>

In your app.js file, we add an initialized function:

$scope.initDetailProvider = function (s, e) { … }

Next, you’ll need to add some code to your function. The first section adds the grid’s max row height; then you’ll define your createDetailCell() function. Finally, you’ll define your function which marks the rows that will have details.

var dp = new wijmo.grid.detail.FlexGridDetailProvider(s);
dp.maxHeight = 250;
dp.createDetailCell = function (row) {
   var cell = document.createElement('div');
   return cell;
};
dp.rowHasDetail = function (row) {
};

Inside your createDetailCell() function call, define a new FlexGrid that displays the details of the row. In between the cell instantiation and your return copy, insert the following code:

 s.hostElement.appendChild(cell);
            var detailGrid = new wijmo.grid.FlexGrid(cell, {
                headersVisibility: wijmo.grid.HeadersVisibility.Column,
                autoGenerateColumns: false,
                itemsSource: $scope.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'}
            ]
            });
            cell.parentElement.removeChild(cell);

Finally, define which rows will have details. The following code goes inside, and in this case, it marks all rows. You can change the modular value to do even or odd.

return row.dataItem.CategoryID % 1 == 0;

Your application should look like the following:

In this example, you used JavaScript to bind the FlexGrid’s items source and insert it into the DetailRow. In the next example, you will use some AngularJS to populate the details of the DetailRow.

View Plnkr for Embedding FlexGrid via Class Sample >>

Embedding a Chart into a Row via Directives

Maybe you'll want to use the FlexGrid to visualize data from the DetailRow. For example, you want to see your stock numbers for a particular product and compare that to what you have on order. In this situation, you want to use a bar or column chart. You don’t need to do anything to your app.js file because you already have a products CollectionView. Add a FlexChart inside your DetailRow directive.

<wj-flex-chart items-source="getProducts($item.CategoryID)" chart-type="Column" stacking="Stacked100pc" binding-x="ProductName">
</wj-flex-chart>

Bind the FlexChart items source to the same getProducts() function, pass it the type of Column. Finally, bind your x axis value to the ProductName. Once you’ve added the FlexChart, add two series to the chart.

<wj-flex-chart-series name="Units In Stock" binding="UnitsInStock">
</wj-flex-chart-series>
<wj-flex-chart-series name="Units On Order" binding="UnitsOnOrder">
</wj-flex-chart-series>

Run the sample and expand your detail row. You’ll see something like the following:

View Plnkr for Embedding FlexChart via Directives >>

Stay tuned for part 2, when we'll cover more advanced features.

Resources

MESCIUS inc.

comments powered by Disqus