Hierarchical Data

Parent Previous Next

In the previous section we saw the power of the datagrid with lazy loaded flat data. That example demonstrated lazily loading flat data. In terms of hierarchical data, this means it demonstrated lazy loading data at the "top level". As you may have guessed, we support this same functionality at the inner (children) levels. Before we get too far ahead, you may be better served by understanding the concept of 'level"


Below is the documentation of the class FlexDataGridColumnLevel:


A class that contains information about a nest level of grid. This includes the columns at this level, information about whether or not to enable paging, footers, filters, the row sizes of each, the property of the dataprovider to be used as the key for selection, the property of the data provider to be used as the children field, the renderers for each of the cells, etc.The Grid always contains at least one level. This is the top level, and is accessible via the columnLevel property of the grid.


One of the most important concepts behind the Architecture of Flexicious Ultimate arose from the fundamental requirement that the product was created for - that is display of Heterogeneous Hierarchical Data.


The notion of nested levels is baked in to the grid via the "columnLevel" property. This is a property of type "FlexDataGridColumnLevel". The 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. This can be demonstrated in the following image.





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. 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 subgrid as well as a level renderer. Bottom line - use nextLevelRenderer only at the innermost level. Our examples demonstrate this.


Another thing to note is that there are two modes in which inner levels work with columns. Either same set of columns shared across each level, or each level has its own set of columns (We call them nested grids vs grouped grids). More information here : http://htmltreegrid.com/newdocs/html/Flexicious%20HTMLTreeGrid.html?AdvancedConfigurationOptionsHier.html


In markup, these would be defined as such:



       <ReactDataGrid ref="{(grid) => {this.grid = grid}}"  ...>

           <ReactDataGridColumnlevel ...>

               <ReactDataGridColumnGroup ...>

                   <ReactDataGridColumn type="checkbox"  />

                   <ReactDataGridColumn enableCellClickRowSelect={"false"} width={"2000"} excludeFromSettings excludeFromExport excludeFromPrint />

               </ReactDataGridColumnGroup ...>

               <ReactDataGridColumnlevel ...>

                   <ReactDataGridColumnlevel ...>

                       <ReactDataGridColumnGroup ...>

                           <ReactDataGridColumn type="checkbox" />

                           ...

                           <ReactDataGridColumn itemEditor={"flexiciousNmsp.DatePicker"} editable editorDataField={"selectedDate"}

                           dataField={"dealDate"} headerText={"Deal Date"} labelFunction={"flexiciousNmsp.UIUtils.dataGridFormatDateLabelFunction"}/>                        

                       </ReactDataGridColumnGroup>

                       <ReactDataGridColumnlevel ...>

                           <ReactDataGridColumnlevel  ...>

                               <ReactDataGridColumn ...>

                                   <ReactDataGridColumn type="checkbox" />

                                   ...

                                   <ReactDataGridColumn editable="true" dataField={"lineItemAmount"} headerText={"Line Item Amount"}

                                   textAlign={"right"} footerAlign={"right"} footerLabelFunction2={"myCompanyNameSpace.fullyLazyLoaded_getFooterLabel"}

                                   labelFunction={"flexiciousNmsp.UIUtils.dataGridFormatCurrencyLabelFunction"}/>

                               </ReactDataGridColumn>

                           </ReactDataGridColumnlevel>

                       </ReactDataGridColumnlevel>

                   </ReactDataGridColumnlevel>

               </ReactDataGridColumnlevel>

           </ReactDataGridColumnlevel>

       </ReactDataGrid>




(Full markup here : http://www.htmltreegrid.com/demo/examples/js/samples/Nested.js)


OR


       <ReactDataGrid refs={(grid) => {this.grid = grid}} ...>

           <ReactDataGridColumnLevel  ... >

               <ReactDataGridColumnGroup ... >

                   <ReactDataGridColumn type="checkbox"   />

                   ....

                   <ReactDataGridColumn itemEditor={"flexiciousNmsp.DatePicker"}

                       dataField={"dueDate"} headerText={"Due Date"} filterControl={"DateComboBox"}

                       labelFunction={"flexiciousNmsp.UIUtils.dataGridFormatDateLabelFunction"} />

                       

               </ReactDataGridColumnGroup>

               <ReactDataGridColumnLevel>

                   <ReactDataGridColumnLevel ... reusePreviousLevelColumns >

                       <ReactDataGridColumnLevel>

                           <ReactDataGridColumnLevel ... reusePreviousLevelColumns>

                           ...

                           </ReactDataGridColumnLevel>

                       </ReactDataGridColumnLevel>

                   </ReactDataGridColumnLevel>

               </ReactDataGridColumnLevel>

           </ReactDataGridColumnLevel>

       </ReactDataGrid>


(Full markup here : http://www.htmltreegrid.com/demo/examples/js/samples/GroupedData.js)



Now, lets look at what a simple configuration with hierarchical data looks like:


Hierarchical data works very similar to flat data, with the exception that the JavaScript object at the top level have a property usually named children that is a pointer to an array of nested objects which represent the children of the top-level objects.  These nested objects in turn can have children of their own which in turn can have children of their own up to any number of nested levels.  The one thing to keep in mind here is that the name of the property that points to the next level children is configurable via the childrenField property.  This defaults to the string “children”  but can be anything as long as it's configured appropriately


Another thing to notice about this example is the use of the enableDynamicLevels flag:

For those of you who are not familiar with what a dynamic tree grid is, (Actually the term is dynamicLevels) - This means that the grid will introspect the data provider to automatically figure out how deep the tree will nest. This is in contrast to other configurations where you explicitly define how "deep" the tree will be, what columns will be at each level, etc. But in case the hierarchy is unknown at design time, the grid is capable of introspecting the data provider and automatically generating the levels at run time. You do this by setting enableDynamicLevels="true" on the grid. However, since the levels are not defined at design time, to be able to manipulate their properties at runtime, we have an event, DYNAMIC_LEVEL_CREATED and DYNAMIC_ALL_LEVELS_CREATED. Both these events are defined on the FlexDataGridEvent class.




<script type="text/javascript">


class Example extends React.Component {

   constructor() {

       this.state = {

           dataProvider: [

               { "id":"5001", "type":"None None None None None None None None None None None None None " ,

               children:[

                   { "id":"5001", "type":"None 1 None 1 None 1 None 1 None 1 None 1 None 1 None 1 None 1"  },

                   { "id":"5002", "type":"Glazed 1 Glazed 1 Glazed 1 Glazed 1 Glazed 1 Glazed 1 Glazed 1 Glazed 1 Glazed 1 Glazed 1" },

                   { "id":"5005", "type":"Sugar 1 Sugar 1 Sugar 1 Sugar 1 Sugar 1 Sugar 1 Sugar 1 Sugar 1" },

                   { "id":"5007", "type":"Powdered Sugar 1 Powdered Sugar 1 Powdered Sugar 1 Powdered Sugar 1 Powdered Sugar 1" },

                   { "id":"5006", "type":"Chocolate with Sprinkles 1 Chocolate with Sprinkles 1 Chocolate with Sprinkles 1 Chocolate with Sprinkles 1" },

                   { "id":"5003", "type":"Chocolate 1 Chocolate 1  Chocolate 1  Chocolate 1  Chocolate 1  Chocolate 1  Chocolate 1  Chocolate 1  Chocolate 1 " },

                   { "id":"5004", "type":"Maple 1 Maple 1  Maple 1  Maple 1  Maple 1  Maple 1  Maple 1  Maple 1  Maple 1  Maple 1 " }

               ]

               },

               { "id":"5002", "type":"Glazed" },

               { "id":"5005", "type":"Sugar" },

               { "id":"5007", "type":"Powdered Sugar" },

               { "id":"5006", "type":"Chocolate with Sprinkles" },

               { "id":"5003", "type":"Chocolate" },

               { "id":"5004", "type":"Maple" }

           ]

       }

   }


   render() {

       return (

           <ReactDataGrid ref={(grid) => {this.grid = grid}} dataProvider={this.state.dataProvider} enableDynamicLevels variableRowHeight

            horizontalScrollPolicy="on" recalculateSeedOnEachScroll enableExport forcePagerRow pageSize="50" enableFilters enableFooters >

               <ReactDataGridColumnLevel enableFooters childrenField={"children"} >

                   <ReactDataGridColumnGroup>

                       <column enableHierarchicalNestIndent dataField="id" headerText="ID" width="100"/>

                       <column dataField="type" headerText="Type" width="100" wordWrap="true"/>

                       <column dataField="type" headerText="Type" />

                   </ReactDataGridColumnGroup>

               </ReactDataGridColumnLevel>

           </ReactDataGrid>

       );

   }

}

</script>


In this example we can see that the top level object with the ID of 5001 has a list of children.