Infragistics jQuery Tree–load on demand, checkboxes and keyboard navigation

Jordan Tsankov / Saturday, January 21, 2012

Enabling load on demand can be very beneficial for your Infragistics jQuery Tree’s performance. Loading on demand will decrease page loading time in two ways:

  1. Additional sub-nodes will not have their HTML elements rendered until the moment they are required to load – meaning the only elements that actually exist are the ones you can visually identify in the tree.
  2. Information that should be loaded in sub-nodes is not pulled from your data source until the tree needs it. This effectively breaks down data into smaller chunks which are loaded faster when required.

With checkboxes next to every node, selection becomes really easy. Even though it’s pretty intuitive to click on something in order to state that you want to mark it as selected, sometimes clicking may be interpreted by the user as having a totally different action ( e.g. sometimes clicking on text loads up a link ). This is where checking things off turns out to be even more practical ! We tick off items in grocery lists, we vote by placing ticks, we take tests by placing ticks – it’s a natural thing for us. Besides, another little thing that checkboxes bring along is that they allow multiple selections – a feat that is not achievable without them.

Sometimes there is a lot of input required on a page. A myriad of editors, radio buttons and dropdowns often make people completely forget about their mouse and focus entirely on the keyboard. When your Infragistics Tree comes on focus, you can efficiently use your directional keys to traverse between nodes.

It’s time to get technical, so let’s get on with it !

Enabling load on demand

To get load on demand working in a tree, you will need to have some data source. It doesn’t matter whether you build your tree on top of an existing <ul> structure or whether you populate it explicitly:

   1: // existing html <ul> structure
   2: <ul id="htmlTarget">
   3:     <li>Item 1</li>
   4:     <li>Item 2</li>
   5:     <li>Item 3
   6:         <ul>
   7:         <li>Sub 1</li>
   8:         <li>Sub 2</li>
   9:         </ul>
  10:     </li>
  11:     <li>Item 4</li>
  12: </ul>
  13:  
  14: $("#htmlTarget").igTree({loadOnDemand: true});
  15:  
  16: // loading local data
  17: var items = [
  18:         { Person: "Bob", Info: [
  19:         { Name: "Favorite Color", Value: "Red" },
  20:         { Name: "Age", Value: 19 },
  21:         { Name: "Favorite Sport", Value: "Football" }
  22:     ]
  23: }];
  24:  
  25: tree.igTree({
  26:     dataSource: items,
  27:     loadOnDemand: true,
  28:     bindings: {
  29:         textKey: "Person",
  30:         valueKey: "Person",
  31:         childDataProperty: "Info",
  32:         bindings: {
  33:             textKey: "Name",
  34:             valueKey: "Value"
  35:         }
  36:     }
  37: });
  38:  
  39: // loading remote data
  40: var data_url = "http://services.odata.org/OData/OData.svc/Categories?$format=json&$callback=?";
  41: var jsonp = new $.ig.JSONPDataSource({ dataSource: data_url, responseDataKey: "d" });
  42:  
  43: tree.igTree({
  44:     dataSource: jsonp,
  45:     checkboxMode: "biState",
  46:     responseDataKey: "d",
  47:     singleBranchExpand: true,
  48:     loadOnDemand: true,
  49:     bindings: {
  50:         textKey: "Name",
  51:         valueKey: "Name",
  52:         childDataProperty: "Products",
  53:         bindings: {
  54:             textKey: "Name",
  55:             valueKey: "Name",
  56:             childDataProperty: "Supplier",
  57:             bindings: {
  58:                 textKey: "Name",
  59:                 valueKey: "Name"
  60:             }
  61:         }
  62:     }
  63: });

All three ways of loading data will produce the desired load-on-demand effect. In each case, you can use any available web page inspector tool and confirm for yourself that the tree is being dynamically populated as opposed to the whole node structure being pre-loaded.

In the snippet above, I would like to make a note about the last example. When you’re using a remote service to fetch data, always use the responseDataKey property if the results come wrapped in an object. For example, if you manually navigate to the URL on line 40, you will see something along these lines:

   1: ?({
   2: "d" : [
   3: {
   4: "__metadata": {
   5: "uri": "http://services.odata.org/OData/OData.svc/Categories(0)", "type": "ODataDemo.Category"
   6: }, "ID": 0, "Name": "Food", "Products": {
   7: "__deferred": {
   8: "uri": "http://services.odata.org/OData/OData.svc/Categories(0)/Products"
   9: }
  10: }
  11: }, {
  12: "__metadata": {
  13: "uri": "http://services.odata.org/OData/OData.svc/Categories(1)", "type": "ODataDemo.Category"
  14: }, "ID": 1, "Name": "Beverages", "Products": {
  15: "__deferred": {
  16: "uri": "http://services.odata.org/OData/OData.svc/Categories(1)/Products"
  17: }
  18: }
  19: }, {
  20: "__metadata": {
  21: "uri": "http://services.odata.org/OData/OData.svc/Categories(2)", "type": "ODataDemo.Category"
  22: }, "ID": 2, "Name": "Electronics", "Products": {
  23: "__deferred": {
  24: "uri": "http://services.odata.org/OData/OData.svc/Categories(2)/Products"
  25: }
  26: }
  27: }
  28: ]
  29: });

It becomes evident that the actual data objects are all pushed into an array which is called “d”. This is a standard practice that is in place since .NET 3.5’s changes to ASP.NET.

So once we know this fact, we can tell our DataSource and our Tree that we expect the results to be wrapped in an array called “d”.

Another very obvious option that we need to set is the loadOnDemand one. This option will let the Infragistics jQuery Tree communicate with the service and pull data as per user interaction. You can see how to enable load on demand in the code snippet above – all three samples have it.

Enabling checkboxes

To make full use of this feature, make sure you understand the different available checkbox modes. Here’s a brief description of the two modes:

biState – This is the regular on/off behavior. A checkbox is either ticked or not, and each checkbox is completely autonomous – it does not affect other nodes’ checkbox status in any way.

triState – This mode has an extra state – in addition to on/off, a checkbox can be partially checked. What this means is: If you check any child node's checkbox, its parent node’s checkbox will be “partially” checked. Simply put – when ticking a node’s checkbox, that selection will cascade to any ancestors and either set their state to partially checked or unchecked ( depending on the initial state of the node ). Cascading works in the opposite way too – if you tick a node’s checkbox , any descendant nodes will become fully ticked too.

Now when you know what each of these modes do – putting that knowledge to use is the next step. You can either skim the large snippet above and see how to enable checkboxes, or just look at this next example:

   1: tree.igTree({
   2:     dataSource: jsonp,
   3:     responseDataKey: "d",
   4:     loadOnDemand: true,
   5:     checkboxMode: "triState"
   6: });

Enabling keyboard navigation

All you have to do in order to enable keyboard navigation is…nothing ! Yeah, that’s right. Keyboard navigation is always on, waiting to be used. To do that, the tree has to be on focus – so either hit the “TAB” key until that happens or just click on any node – either of these will bring focus on the tree. When that happens, the following keys may be used to traverse the tree:

  • left/right keys are used to collapse/expand nodes, respectivey.
  • up/down keys are used to move to previous/next node, respectively.
  • Space is used to change the state of a node’s checkbox, provided that checkboxes are enabled.

Conclusion

By this point, you should have a somewhat clear idea about when and how to use load on demand. If you would like to see some examples of working code – I strongly suggest visiting this link, as well as v. Both will show you some of the official Infragistics jQuery Tree samples about load-on-demand.

InfragisticsTreeLoD_KB.zip