Hierarchical Grids

Previous Next

As discussed elsewhere in this guide, display of hierarchical data is among the most powerful features of the ReactDataGrid. There are two different types of hierarchical grids:



Nested:

Grouped:


One of the most important concepts behind the Architecture of the grid arose from the fundamental requirement that we created the product for - that is display of Hierarchical Data. The notion of nested levels is baked in to the grid via the "columnLevel" property. This is a property of type "FlexDataGridColumnLevel". This grid always has at least one column level. This is also referred to as the top level, or the root level. In flat grids (non hierarchical), this is the only level. But in nested grids, you could have any number of nested levels. The columns collection actually belongs to the columnLevel, and since there is one root level, the columns collection of the grid basically points to the columns collection of this root level. So if there is a grid like the Nested example above, where the top level shows Organizations, the next one shows Projects, and the next one Invoices, and the final inner most shows Invoice Line Items, we are basically looking at a grid with 4 levels. Below is the configuration for a grid like this one.

<ReactDataGrid ref={(grid) => {this.grid = grid}} enablePrint={true} enableMultiColumnSort={true}>

   <ReactDataGridColumnLevel enableFilters={true} enablePaging={true} initialSortField={"legalName"}

       pageSize={20} childrenField={deals} enableFooters={true} selectedKeyField={id}>

       ...

       <ReactDataGridColumnLevel childrenField={"invoices"} enableFooters={true} selectedKeyField={"id"} nestIndent={30}

           initialSortField={"dealDate"} initialSortAscending={false} parentField={"customer"}>

           ...

           <ReactDataGridColumnLevel childrenField={"lineItems"} enableFooters={true} enablePaging={true} pageSize={3}

               selectedKeyField={"id"} parentField={"deal"} nestIndent={30}>

               ...

               <ReactDataGridColumnLevel enableFooters={true} selectedKeyField={"id"} parentField={"invoice"} nestIndent="30">

                   ...

               </ReactDataGridColumnLevel>

           </ReactDataGridColumnLevel>

       </ReactDataGridColumnLevel>

   </ReactDataGridColumnLevel>

</ReactDataGrid>




On the other hand, for the "grouped" grids, the inner levels do not have a column of their own, instead using the top level columns using the reusePreviousLevelColumns property.



   <ReactDataGrid ref={(grid) => {this.grid = grid}} enablePrint={true} horizontalGridLines={true} ...>

       <ReactDataGridColumnLevel enableFilters={true} enablePaging={true} pageSize={20} childrenField={deals}

           selectedKeyField={id} reusePreviousLevelColumns={true}>

           ...

           <ReactDataGridColumnLevel childrenField={invoices} selectedKeyField={id} reusePreviousLevelColumns={true}>

               ...

               <ReactDataGridColumnLevel enableFooters={true} enablePaging={true} pageSize={5}

                   selectedKeyField={id} reusePreviousLevelColumns={true}>

                   ...

               </ReactDataGridColumnLevel>

           </ReactDataGridColumnLevel>

       </ReactDataGridColumnLevel>

   </ReactDataGrid>




There is one field that is crucial to provide on the level: The childrenField. This is The property of the parent level object, that identifies the children that should be displayed on the next level. This is only required if the collection is not a hierarchical view. Please note, in server mode, this property is also the "storage" for the lazy loaded children.


The FlexDataGridColumnLevel class has a "nextLevel" property, which is a pointer to another instance of the same class, or a "nextLevelRenderer" property, which is a reference to a ClassFactory the next level. Please note, currently, if you specify nextLevelRenderer, the nextLevel is ignored. This means, at the same level, you cannot have both a nested sub-grid as well as a level renderer. Bottom line - use nextLevelRenderer only at the innermost level. For an example, refer to http://www.reactdatagrid.com/demo/#LevelRenderer


Sample configuration for a level renderer


<ReactDataGrid ref={(grid) => {this.grid = grid}} preferencePersistenceKey={"levelRenderers2"} enablePreferencePersistence={true}

   enablePrint={true} enableDrillDown={true} enableExport={true} enableCopy={true}

   oncreationComplete={this.myCompanyNameSpace.levelRenderers2_creationCompleteHandler.bind(this)}>

   <ReactDataGridColumnLevel enableFilters={true} enablePaging={true} enableFooters={true} pageSize={20}

       childrenField={"deals"}  selectedKeyField={"id"}

       rendererHorizontalGridLines={true} rendererVerticalGridLines={true}

       nextLevelRenderer={this.myCompanyNameSpace.LevelRenderers2_NextLevelRenderer2.bind(this)} levelRendererHeight={120}>

       <ReactDataGridColumn type={"checkbox"}  />

       <ReactDataGridColumn enableCellClickRowSelect={false} columnWidthMode={"fitToContent"}

           selectable={true} dataField={"id"} headerText={"ID"} filterControl={TextInput} />

       <ReactDataGridColumn truncateToFit={true}  enableCellClickRowSelect={false}

           columnWidthMode={"fitToContent"} selectable={true} dataField={"legalName"} headerText={"Legal Name"} />

       <ReactDataGridColumn dataField={headquarterAddress.line1} headerText={"Address Line 1"}

           footerLabel={"Count:"} footerOperation={"count"} />

       <ReactDataGridColumn dataField={headquarterAddress.line2} headerText={"Address Line 2"}/>

       <ReactDataGridColumn dataField={headquarterAddress.city.name} headerText={"City"}

           filterControl={MultiSelectComboBox} filterComboBoxBuildFromGrid={true} filterComboBoxWidth={150} />

       <ReactDataGridColumn dataField={headquarterAddress.state.name} headerText={"State"}

           filterControl={MultiSelectComboBox} filterComboBoxBuildFromGrid={true} filterComboBoxWidth={150} />

       <ReactDataGridColumn dataField={headquarterAddress.country.name} headerText={"Country"}

           filterControl={MultiSelectComboBox} filterComboBoxBuildFromGrid={true} filterComboBoxWidth={150} />

   </ReactDataGridColumnLevel>

</ReactDataGrid>


This generates a grid like this:


There are also two different modes of loading hierarchical data.


The itemLoadMode is not to be confused with filterPageSortMode, which determines the top level records only.


When itemLoadMode is server, you may want to set childrenCountField.

A property on the object that identifies if the object has children. Only needed in itemLoadMode=server In lazy loaded hierarchical grids levels, the child level items are loaded when the user actually expands this level for the first time. In scenarios where it is known initially that there are children, set this property to the value of the object that identifies whether there are children. If this property is set, the expand collapse icon will be drawn only when the value of this property on the object returns an integer greater than zero. Otherwise, the level will always draw the expand collapse icon.