Wijmo

MultiRow 101

This page shows how to get started with Wijmo's MultiRow control.

Getting Started

The MultiRow control extends conventional grid layouts by using multiple rows to represent each data item.

The MultiRow control allows users to see and edit data in a tabular form, just like other conventional grids. But, MultiRow is different from these grids in a way that it allows you to bind each data item to multiple rows, creating form-like interfaces that can display a large number of columns with minimal horizontal scrolling.

The MultiRow control extends the FlexGrid control, so if you know how to use FlexGrid, you will be able to use MultiRow in no time. The main new property is layoutDefinition, which takes an object that describes the layout of the grid rows and cells.

The MultiRow control is not a simple replacement for conventional grids; it is a specialized tool that fits some particular scenarios really well.

To use the MultiRow control in your applications, add references to the wijmo, wijmo.grid, and wijmo.grid.multirow modules, then instantiate MultiRow controls by giving them host element on the page, or add wj-multi-row directives if you are using AngularJS:

HTML
<div id="multirow"></div> <div id="ldComboBox"></div> <div id="desc"></div>
JS
var multirow = new wijmo.grid.multirow.MultiRow('#multirow', { itemsSource: appData.orders, layoutDefinition: appData.layoutDefs.currentItem.def }); var ldComboBox = new wijmo.input.ComboBox('#ldComboBox', { itemsSource: appData.layoutDefs, displayMemberPath: 'name', selectedIndexChanged: function (s, e) { var layoutDef = appData.layoutDefs.currentItem; if (layoutDef) { multirow.layoutDefinition = layoutDef.def; setText('desc', layoutDef.description); } } }); setText('desc', appData.layoutDefs.currentItem.description);

Result (live):

The layoutDefinition property specifies the layout of the cells in the grid. It contains an array of cell group objects. Each cell group specifies how many columns the group should span, and the cells that make up each group.

The image below illustrates how a cell group is interpreted and turned into a grid layout:

cell group

The group spans three grid columns. It contains six cells with different spans. When generating the layout, the grid fits as many cells as possible in each row, and wraps to the next row when the group span is reached. The last cell in each row is automatically expanded to fill colspan of the group. The process is similar to wrapping of text to create a paragraph.

The same process is applied to every group in the layoutDefinition object.

Collapsible Column Headers

By default, the MultiRow control creates column headers that span multiple rows and shows the header for each cell defined in the layoutDefinition.

These cell-specific column headers may be used to sort or filter the data as you would do in a conventional grid.

In some cases, you may want to collapse the column headers to a single line, showing only the group names rather than individual cells. This saves space at the expense of having individual cell headers. To collapse the column headers, set the collapsedHeaders property to true. In these scenarios, remember to set the header property on the groups in order to avoid empty column headers.

HTML
<div id="chMultirow"></div> <label for="cbCollapsedHeaders"> Collapsed Headers </label> <div id="cbCollapsedHeaders"></div> <br /> <label for="cbshowHeaderCollapseButton"> Show Header Collapse Button </label> <input type="checkbox" checked id="cbshowHeaderCollapseButton">
JS
var chMultirow = new wijmo.grid.multirow.MultiRow('#chMultirow', { itemsSource: appData.orders, layoutDefinition: appData.ldThreeLines, collapsedHeaders: true, showHeaderCollapseButton: true, collapsedHeadersChanged: function (s, e) { cbCollapsedHeaders.selectedValue = s.collapsedHeaders; } }); // handle combo var cbCollapsedHeaders = new wijmo.input.ComboBox('#cbCollapsedHeaders', { displayMemberPath: 'name', selectedValuePath: 'value', itemsSource: [ { name: 'true', value: true }, { name: 'false', value: false }, { name: 'null', value: null } ], selectedValue: chMultirow.collapsedHeaders, selectedIndexChanged: function (s, e) { chMultirow.collapsedHeaders = s.selectedValue; } }); // handle checkbox document.getElementById('cbshowHeaderCollapseButton').addEventListener('click', function (e) { chMultirow.showHeaderCollapseButton = e.target.checked; });

Result (live):


Styling Records, Groups, and Cells

In most of the applications, you would want to show where each record and group starts or ends. The MultiRow control enables this by adding CSS class names to cell elements in the first and last row/column of each group. The class names are wj-record-start, wj-record-end, wj-group-start, and wj-group-end.

The example below shows how you can use these class names in CSS rules to customize the appearance of the record and group delimiters. It also shows how you can use the standard cssClass property to customize the appearance of specific cells within groups:

HTML
<div id="styleMultirow" class="multirow-css"></div>
JS
var styleMultirow = new wijmo.grid.multirow.MultiRow('#styleMultirow', { itemsSource: appData.orders, layoutDefinition: appData.ldThreeLines });
CSS
/* custom styling for a MultiRow */ .multirow-css .wj-cell.wj-record-end:not(.wj-header) { border-bottom: 1px solid #000; /* thin black lines between records */ } .multirow-css .wj-cell.wj-group-end { border-right: 2px solid #00b68c; /* thick green lines between groups */ } .multirow-css .wj-cell.id { color: #c0c0c0; } .multirow-css .wj-cell.amount { color: #014701; font-weight: bold; } .multirow-css .wj-cell.email { color: #0010c0; text-decoration: underline; }

Result (live):

Grouping

The MultiRow control supports CollectionView-based grouping just like FlexGrid. To use grouping, create a CollectionView based on the raw data and add one or more GroupDescription objects to the GroupDescriptions array of the collection.

HTML
<div id="groupMultirow"></div> <label> <input type="checkbox" checked id="cbShowGroup"> Show Groups </label> <br /> <button class="btn" id="btnCollapse"> Collapse All </button> <button class="btn" id="btnExpand"> Expand All </button>
JS
var groupMultirow = new wijmo.grid.multirow.MultiRow('#groupMultirow', { itemsSource: appData.groupedOrders, layoutDefinition: appData.ldThreeLines, showGroups: true, groupHeaderFormat: '{name}: {value} ({count:n0} items)' }); // toggle show groups document.getElementById('cbShowGroup').addEventListener('click', function (e) { groupMultirow.showGroups = e.target.checked; }); // collapse/expand all document.getElementById('btnCollapse').addEventListener('click', function (e) { groupMultirow.collapseGroupsToLevel(0); }); document.getElementById('btnExpand').addEventListener('click', function (e) { groupMultirow.collapseGroupsToLevel(10); });

Result (live):


Filtering

The MultiRow control supports filtering just like FlexGrid.

Filtering is provided by the wijmo.grid.filter.FlexGridFilter class. To add filtering UI to MultiRow, create a FlexGridFilter and pass MultiRow as a parameter in the constructor.

If you are using AngularJS, you can also add a filter to the grid by embedding a wj-flex-grid-filter directive as a child of the grid's directive.

HTML
<div id="filterMultirow"></div>
JS
var filterMultirow = new wijmo.grid.multirow.MultiRow('#filterMultirow', { itemsSource: appData.orders, layoutDefinition: appData.ldThreeLines }); var filter = new wijmo.grid.filter.FlexGridFilter(filterMultirow);

Result (live):

Row and Column Freezing

The MultiRow control allows you to freeze rows and columns so they remain in view as the user scrolls the grid. Frozen cells can be edited and selected as regular cells, exactly as in Excel and in the FlexGrid control.

This example allows you to toggle whether the first group of rows and columns should be frozen.

HTML
<div id="freezeMultirow"></div> <button class="btn btn-default" id="btnFreeze"> Freeze </button>
JS
var freezeMultirow = new wijmo.grid.multirow.MultiRow('#freezeMultirow', { itemsSource: appData.orders, layoutDefinition: appData.ldTwoLines }); document.getElementById('btnFreeze').addEventListener('click', function (e) { freezeMultirow.frozenColumns = freezeMultirow.frozenColumns ? 0 : 2; freezeMultirow.frozenRows = freezeMultirow.frozenRows ? 0 : 2; e.target.textContent = freezeMultirow.frozenRows == 0 ? 'Freeze' : 'Unfreeze'; });

Result (live):

Paging

The MultiRow control supports paging through the IPagedCollectionView interface, which is nearly identical to the one in .NET. To enable paging, set the IPagedCollectionView.pageSize property to the number of items you want to display on each page, and provide a UI for navigating the pages.

In this example, we use JavaScript to show four items per page. We add navigation buttons, and call IPagedCollectionView method in the button click directives. We use the pageIndex and pageCount properties to show the current page and total number of pages.

HTML
<div id="pageMultirow" style="max-height:800px"></div> <div class="btn-group"> <button type="button" class="btn" id="firstBtn"> <span class="glyphicon glyphicon-fast-backward"></span> </button> <button type="button" class="btn" id="previousBtn"> <span class="glyphicon glyphicon-step-backward"></span> </button> <button type="button" class="btn" id="numBtn" disabled style="width:100px"></button> <button type="button" class="btn" id="nextBtn"> <span class="glyphicon glyphicon-step-forward"></span> </button> <button type="button" class="btn" id="lastBtn"> <span class="glyphicon glyphicon-fast-forward"></span> </button> </div>
JS
var pagedOrders = appData.pagedOrders; var pagingMultirow = new wijmo.grid.multirow.MultiRow('#pageMultirow', { itemsSource: pagedOrders, layoutDefinition: appData.ldThreeLines }); // paging buttons document.getElementById('firstBtn').addEventListener('click', function (e) { pagedOrders.moveToFirstPage(); }); document.getElementById('previousBtn').addEventListener('click', function (e) { pagedOrders.moveToPreviousPage(); }); document.getElementById('nextBtn').addEventListener('click', function (e) { pagedOrders.moveToNextPage(); }); document.getElementById('lastBtn').addEventListener('click', function (e) { pagedOrders.moveToLastPage(); }); // update page text now and when the current page changes updatePageText(); pagedOrders.collectionChanged.addHandler(function () { updatePageText(); }); pagedOrders.pageChanged.addHandler(function () { updatePageText(); }); function updatePageText() { var text = wijmo.format('{index:n0} / {count:n0}', { index: pagedOrders.pageIndex + 1, count: pagedOrders.pageCount }); setText('numBtn', text); }

Result (live):

Adding and Deleting Records

The MultiRow control supports the allowAddNew and allowDelete properties provided by the FlexGrid control.

Setting the allowAddNew property to true causes the grid to display a set of 'new row template' rows at the bottom of the grid. When user starts editing a cell in the new row template, a new item is added to the source collection. When user finishes editing the new item by moving the selection to another row or the focus to another control, the new item is committed.

Setting the allowDelete property to true causes the grid to monitor key presses and to delete the current row if user presses the 'Delete' key while an entire row is selected.

HTML
<div id="adMultirow"></div> <label> <input id="ckbAllNew" type="checkbox" checked > Allow Add New </label> <br /> <label> <input id="ckbAllDelete" type="checkbox" checked > Allow Delete </label>
JS
var adMultirow = new wijmo.grid.multirow.MultiRow('#adMultirow', { itemsSource: appData.addNewOrders, layoutDefinition: appData.ldThreeLines, showGroups: false, allowAddNew: true, allowDelete: true }); // handle buttons document.getElementById('ckbAllNew').addEventListener('click', function (e) { adMultirow.allowAddNew = e.target.checked; }); document.getElementById('ckbAllDelete').addEventListener('click', function (e) { adMultirow.allowDelete = e.target.checked; });

Result (live):