Dijit Tree with Multi State Checkboxes


NOTE:

The new and fully AMD compliant version of the Dijit CheckBox Tree can be found HERE. Please refer to the updated version going forward.

Introduction

This article is a follow-up on my previous blog regarding a dijit tree with checkboxes. In the past couple of weeks I received a number of requests if it would be possible to get the checkbox tree with so called multi or triple state checkboxes. By default a checkbox has two states:

  1.  True (checked)
  2.  False (unchecked)

This BTW: applies to the default HTML checkbox as well as the dijit checkbox so in order to make a multi/triple state checkbox work we have to create our own checkbox that holds an additional state. Second, we have to be able to visually represent the third state. Going forward I will refer to this third state as the 'mixed' state.

Multi State Demo Download Button

Click here to take a quick look at a demo. If you want to leave a comment or have a question regarding this article or the previous one, please visit my blog. The source package for the Checkbox Tree with multi state checkboxes can be downloaded here.

The Basics

The default dijit checkbox uses the standard HTML checkbox controls but overlays the visual image with its own sprite and apply some CSS styling. We are going to use the same concept by extending the dijit checkbox widget, create a new sprite and associated CSS classes. To make it real fancy I'm going to create separate sprites for each dijit theme. Having said that I still want to be able to support the default HTML checkbox, the visual aspect of a mixed state will not be supported BUT at the application level you will be able to check if the HTML checkbox is in a mixed state.

For this tutorial I'm going to use the dojo version 1.4 source of our CheckBoxTree which can be downloaded here, just in case you are wondering: will there be a dojo 1.3.2 version available of the multi state checkbox tree, the answer is yes.

The Multi State Checkbox

 I'm going to include the extended dijit checkbox widget in our CheckBoxTree source file as I currently don't have any plans for using the multi state checkbox anywhere else. However, it is very easy to extract it if you want to. And now for some code:

  1 dojo.provide("tmpdir.CheckBox");
  2 dojo.provide("tmpdir.CheckBoxTree");
  3 dojo.provide("tmpdir.CheckBoxStoreModel");
  4 
  5 dojo.require("dijit.Tree");
  6 dojo.require("dijit.form.CheckBox");
  7 dojo.require("dijit.tree.ForestStoreModel");
  8 
  9 dojo.declare( "tmpdir.CheckBox", dijit.form.CheckBox,
 10 {
 11   baseClass: "tmpdirCheckBox",
 12 
 13   value: "unchecked",
 14 
 15   _setStateClass: function(){
 16     var newStateClasses = this.baseClass.split(" ");
 17 
 18     function multiply(modifier){
 19       newStateClasses = newStateClasses.concat(dojo.map(newStateClasses,
 20         function(c){ return c+modifier; }),
 21         "dijit"+modifier);
 22     }
 23 
 24     if(this.state){  multiply(this.state); }
 25     if(this.attr('value') == "mixed" ){
 26       multiply("Mixed");
 27     } else if(this.checked){
 28       multiply("Checked");
 29     }
 30     if(this.disabled){
 31       multiply("Disabled");
 32     }else if(this._active){
 33       multiply(this.stateModifier+"Active");
 34     }else{
 35       if(this._focused){
 36         multiply("Focused");
 37       }
 38       if(this._hovering){
 39         multiply(this.stateModifier+"Hover");
 40       }
 41     }

On line 1 we tell dojo that our CheckBoxTree file also provides our new checkbox using the same namespace (tmpdir) as we did before. We include the dijit checkbox on line 6 and declare the new checkbox on line 9 which inherits from dijit.from.Checkbox.

On line 11 we define the base class for our checkbox widget. This will distinguish our checkbox from the default dijit checkbox allowing us to create our own CSS classes and thus introduce the third (mixed) state. On line 13 we set the value attribute to "unchecked". We are going to use the checkbox value attribute to hold the mixed state which can be either "checked", "unchecked" or "mixed". The value attribute maps the standard value property of  the default HTML checkbox and therefore at the application layer you can use this value to determine if a checkbox is in a mixed state regardless if you use our dijit style checkbox or the default HTML checkbox. (more on this later).

On line 15 we overwrite the _setStateClass method which will generate the appropriate CSS classes depending on the current state of the checkbox. For example, if the checkbox is checked it will generate a CSS class "tmpdirCheckBoxMixed" if on the other hand the checkbox is in a mixed state it will generate a CSS class "tmpdirCheckBoxMixed" or we could get a state like "tmpdirCheckBoxMixedHover".

Next we are going to overwrite the default  set and get ValueAttr functions in order to be able to use the checkbox value attribute to hold our mixed state.

 63   _setValueAttr: function( newValue){
 64 
 65     if(typeof newValue == "string"){
 66       this.value = newValue;
 67       dojo.attr(this.focusNode, 'value', newValue);
 68     }
 69   },
 70 
 71   _getValueAttr: function(){
 72     return this.value;
 73   }

The default _setValueAttr method also manipulates the 'checked' attribute of the checkbox and that is something we don't want. Believe it or not but that's all we have to do for our extended checkbox, next we will work on our CSS class definitions and create new sprites for our checkbox.

CSS Classes and Sprites

First we have to create a couple of new directories to support our creative work. In your tmpdir directory create a subdirectory called 'themes' and the themes directory needs another subdirectory for each dijit theme. Finally each dedicated themes directory will have a subdirectory called 'images'. Your directory structure should look like this:

Directory Structure

This directory structure follows the dojo/dijit directory structure, if you want to change it feel free to do so but for this tutorial we are going to use the above structure. In the \themes\nihilo\ directory create a new file called tmpdir.css and add the following lines:

  1 /*
  2  *  Adds cosmetic styling to tmpdir. Users may swap with a custom theme CSS file.
  3 */
  4 @import url("Checkbox.css");

In the same \themes\nihilo\ directory create a new file call Checkbox.css and add the follow class definitions:

  1 /*
  2  *  tmpdir CheckBox Widgets CSS
  3  *
  4  *  Order of images in the sprite (from L to R):
  5  *    checkbox  normal    - checked
  6  *                        - unchecked
  7  *                        - mixed
  8  *              disabled  - checked
  9  *                        - unchecked
 10  *                        - mixed
 11  *              hover     - checked
 12  *                        - unchecked
 13  *                        - mixed
 14 */
 15 .nihilo .tmpdirCheckBox,
 16 .nihilo .tmpdirCheckBoxIcon {
 17   background-image: url('images/spriteCheckbox.gif'); /* sprite image */
 18   background-repeat: no-repeat;
 19   width: 16px;
 20   height: 16px;
 21   margin: 0;
 22   padding: 0;
 23 }
 24 
 25 .nihilo .tmpdirCheckBox,
 26 .nihilo .tmpdirCheckBoxIcon {
 27   /* unchecked */
 28   background-position: -16px;
 29 }
 30 
 31 .nihilo .tmpdirCheckBoxChecked,
 32 .nihilo .tmpdirCheckBoxIcon {
 33   /* checked */
 34   background-position: 0px;
 35 }
 36 
 37 .nihilo .tmpdirCheckBoxDisabled {
 38   /* disabled */
 39   background-position: -48px;
 40 }
 41 
 42 .nihilo .tmpdirCheckBoxCheckedDisabled {
 43   /* disabled but checked */
 44   background-position: -48px;
 45 }
 46 
 47 .nihilo .tmpdirCheckBoxMixed {
 48   /* checked & mixed */
 49   background-position: -32px;
 50 }
 51 
 52 .nihilo .tmpdirCheckBoxMixedDisabled {
 53   /* mixed & Disabled*/
 54   background-position: -64px;
 55 }
 56 
 57 .nihilo .tmpdirCheckBoxHover {
 58   /* hovering over an unchecked enabled checkbox */
 59   background-position: -112px;
 60 }
 61 
 62 .nihilo .tmpdirCheckBoxCheckedHover {
 63   /* hovering over a checked enabled checkbox */
 64   background-position: -96px;
 65 }
 66 
 67 .nihilo .tmpdirCheckBoxMixedHover {
 68   /* checked & mixed */
 69   background-position: -128px;
 70 }

The only thing missing from a creative standpoint is the sprite itself which we declare as our background image on line 17. A sprite is basically a single image composed of multiple smaller images, loading a single sprite instead of multiple smaller images improves performance, creates less overhead and eliminates screen flickering. There are many, many image editors on the market you could use to create the sprite but I prefer to use IconWorkshop from Axialis because the professional version has special support for sprites or Image strips as they call them. Lets create the spriteCheckbox.gif file in the \themes\nihilo\images directory.

spritCheckbox Image

As you can tell from the above image the sprite is composed of 9 smaller images, each 16 pixels high and wide representing the different states of our checkbox. The three images on the right are the hover states which currently are the same as the enabled states on the left. Feel free to adopt the image to your own needs, both the PNG and GIF version are included in the source package.

You will have to repeat the above steps for the other dijit themes Soria and Tundra but I guess you get the picture and don't forget to replace '.nihilo' in the CSS file with the appropriate theme you are creating. (i.e: '.tundra' and '.soria')

Update The Checkbox Tree

To incorporate the new checkbox widget in our tree we will have to make enhancements to all three components of our tree, these components are:

  1. The Model
  2. The Tree Nodes
  3. The Tree

Update The Model

The first thing we will have to do is to introduce a new attribute for each store item which will hold the additional mixed state of our store item. As I said in the previous tutorial the data store and model have no direct relationship to any of the TreeNodes or the associated checkboxes (remember the MVC pattern). Also, as of dojo 1.4 there may actually be multiple checkboxes referring to, or should I say representing, a single store item. 

  1   checkboxAll: true,
  2   checkboxState: false,
  3   checkboxRoot: false,
  4   checkboxStrict: true,
  5   checkboxIdent: "checkbox",
  6   checkboxMState: "mixed",

On line 6 we introduce a new attribute to our model called 'checkboxMState' which holds the name of the attribute we will be using to store the mixed state for each store item. Typically there is not need to overwrite the 'checkboxMState' attribute unless you are planning on using the attribute name "mixed" in your Json file. If so, you will have to overwrite the checkboxMState value when creating the model.

First we need to enhance the getCheckboxState method to support the additional mixed state.

 99   getCheckboxState: function( storeItem) {
100     var state = { checked: undefined, mixed: false };  
101 
102     if ( storeItem == this.root ) {
103       if( typeof(storeItem.checkbox) == "undefined" ) {
104         this.root.checkbox = undefined;    
105         this.root.mixedState = false;
106         if( this.checkboxRoot ) {
107           this._setCheckboxState( storeItem, this.checkboxState, false );
108           state.checked = this.checkboxState;
109         }
110       } else {
111         state.checked = this.root.checkbox;
112         state.mixed    = this.root.mixedState;
113       }
114     } else {  
115       state.checked = this.store.getValue(storeItem, this.checkboxIdent);
116       state.mixed    = this.store.getValue(storeItem, this.checkboxMState);
117       if( state.checked == undefined && this.checkboxAll) {
118         this._setCheckboxState( storeItem, this.checkboxState, false );
119         state.checked = this.checkboxState;
120       }
121     }
122     return state  
123   },

Instead of passing two states around we create a object called 'state' with two properties: checked and mixed. On line 111 and 112 we copy the store item states to our new object and return it at line 122. Now that we can retrieve the additional state we must also be able to store it.

125   _setCheckboxState: function( storeItem,  newState,  mixedState ) {
126     var stateChanged = true;
127 
128     if( storeItem != this.root ) {
129       var currState = this.store.getValue(storeItem, this.checkboxIdent);
130       var currMixed = this.store.getValue(storeItem, this.checkboxMState);
131       if( (currState != newState || currMixed != mixedState) && 
              (currState !== undefined || this.checkboxAll) ) {
132         this.store.setValue(storeItem, this.checkboxIdent, newState);
133         this.store.setValue(storeItem, this.checkboxMState, mixedState);
134       } else {
135         stateChanged = false;
136       }
137     } else {  
138       if(( this.root.checkbox != newState || this.root.mixedState != mixedState) &&
139          ( this.root.checkbox !== undefined || this.checkboxRoot ) ) {
140         this.root.checkbox   = newState;
141         this.root.mixedState = mixedState;
142       } else {
143         stateChanged = false;
144       }
145     }
146     if( stateChanged ) {  
147       this.onCheckboxChange(storeItem, mixedState);
148     }
149     return stateChanged;
150   },

The most important thing with the updated _setCheckboxState method is that we now will  have to validate BOTH states in order to determine if an update to the actual checkbox(es) is required. For example: if a child checkbox is checked/unchecked the parent's checked state may not change but it could alter its mixed state and thus we will have to let the tree know it needs to update the parent checkbox(es).

The next method of our model we need to address is the _updateParentCheckbox. Here is were we determine if a checkbox gets a mixed state, only parent checkboxes can get a mixed state. If any child has a mixed state the parent will automatically get the mixed state too regardless of the state of the other children.

171   _updateParentCheckbox: function( storeItem ) {
172     var parents = this._getParentsItem( storeItem );
173     dojo.forEach( parents, function( parentItem ) {
174       this.getChildren( parentItem, dojo.hitch( this,
175         function(children) {
176           var hasChecked     = false,
177             hasUnChecked   = false,
178             isMixed      = false;
179           dojo.some( children, function(child) {
180             state = this.getCheckboxState(child);
181             isMixed |= state.mixed;
182             switch( state.checked ) {  
183               case true:
184                 hasChecked = true;
185                 break;
186               case false:
187                 hasUnChecked = true;
188                 break;
189             }
190             return isMixed;
191           }, this );
192           isMixed |= !(hasChecked ^ hasUnChecked);
193           if( this._setCheckboxState( parentItem, isMixed ? true: hasChecked, 
                                                      isMixed ? true: false ) ) {
194             this._updateParentCheckbox( parentItem );
195           }
196         }),
197         function(err) {
198           console.error(this, ": fetching mixed state: ", err);
199         });
200     }, this );
201   },

If a store item gets a mixed state, by default it will also enter the checked state (line 193). We could have gone both ways but if you opt to use default HTML checkboxes (which do not support the visual aspect of a mixed state) at least you can SEE some child is checked if the parent branch is collapsed. I guess this is like the glass is half full/empty discussion. On lines 182-189 we explicitly check for 'true' or 'false' as the checked state could also be 'undefined' in which case we need to ignore it. Remember, the undefined state occurs when no 'checkbox' attribute was specified for the store item in the Json file and the model 'checkboxAll' attribute is set to false.

The last changes I made to the model is how the initial store data validation takes place. During some performance testing I found that loading the entire Json file at once, instead of partial or lazy loading, offered by far the best performance. On average loading the file this way is about 5-6 times faster than partial loading. Also, keep in mind that if a strict parent-child checkbox relation is required (which is the default) we will have to load the file first anyway to perform our initial store data validation. As a result I broke the original validateData method into two pieces.

218   validateData: function( storeItem,  scope ) {
219 
220     if( scope.checkboxStrict ) {
221       try {
222         scope.store._forceLoad();    
223       } catch(e) {
224         console.log(e);
225       }
226       dojo.hitch( scope, scope._validateStore ) ( storeItem );
227     }
228   },

As before we first check if a strict parent-child checkbox relationship is required. If so, we'll try a forced load followed by a call to the second part of our validation, now called _validateStore.

230   _validateStore: function( storeItem ) {
231     this.getChildren( storeItem, dojo.hitch( this,
232       function(children) {
233         var hasGrandChild = false,
234           oneChild    = null;
235         dojo.forEach( children, function( child ) {
236           if( this.mayHaveChildren( child )) {
237             this._validateStore( child );
238             hasGrandChild = true;
239           } else {
240             oneChild = child;
241           }
242         },this );
243         if( !hasGrandChild && oneChild ) {    
244           this._updateParentCheckbox( oneChild );
245         }
246       }),
247       function(err) {
248         console.error(this, ": validating checkbox data: ", err);
249       }
250     );
251   },

We walk down to the lowest branch of the tree and request a parent update for at least one child on each branch. The updateParentCheckbox method will go back up the tree all the way to the root.

Update The Tree Nodes

In the original version of our Checkbox Tree the Tree Node simply created a HTML checkbox and inserted it into the DOM. In this episode we are going to offer the option of using our enhanced dijit checkbox widget or use the default HTML checkbox. In addition, I wanted to offer the option to hide the Open/Closed folder icon and/or the leaf icon preceding the node label.

Folder Open/Close Icon

In order to accomplish these additional requirements we are going to introduce four more attributes to our Tree:

Attribute Default
checkboxStyle "dijit"
branchIcons true
nodeIcons true
checkboxMultiState true

Lets go ahead and update our _createCheckbox method of the CheckBoxTreeNode widget.

258 dojo.declare( "tmpdir._CheckBoxTreeNode", dijit._TreeNode,
259 {
260   _checkbox: null,
261 
262   _createCheckbox: function() {
263     var  state = this.tree.model.getCheckboxState( this.item );
264     if( state.checked !== undefined ) {
265       if (this.tree.checkboxStyle == "dijit" ) {
266         this._checkbox = new tmpdir.CheckBox().placeAt(this.expandoNode,'after');
267       } else {
268         this._checkbox = dojo.doc.createElement('input');
269         this._checkbox.className = 'tmpdirHTMLCheckBox';
270         this._checkbox.type      = 'checkbox';
271         dojo.place(this._checkbox, this.expandoNode, 'after');
272       }
273       this._setCheckedState( state );
274     }
275     if( this.isExpandable ) {
276       if ( !this.tree.branchIcons ) {
277         dojo.removeClass(this.iconNode,"dijitTreeIcon");
278       }
279     } else {
280       if( !this.tree.nodeIcons ) {
281         dojo.removeClass(this.iconNode,"dijitTreeIcon");
282       }
283     }
284   },

On line 263, as before, we fetch the checkbox state from the store however, this time we get an object back instead of a simple state. If the checked state is undefined no checkbox is required for this tree node. On line 265 we check the new 'checkboxStyle' attribute to determine what type of checkbox is needed. On line 275 we first check if this particular tree node is expandable (is it a parent checkbox?), than if the Open/Closed Folder or leaf icon aren't required we simply remove the appropriate CSS class from the icon Node.

Previously, when a store item changed state the model would inform the Tree and the Tree would then simply update the checkbox checked state accordingly. This time around we need a little more sophisticated approach because we are now dealing with two states and two checkbox styles each requiring different ways of storing the state information. We add a new method to the CheckBoxTreeNode called _setCheckedState which will handle the updates for the actual checkboxes. This method will be called by the Tree as soon as it receives an update notification from the model. 

286   _setCheckedState: function(  state ) {
287 
288     if( this.tree.checkboxStyle == "dijit" ) {
289       if( this.tree.checkboxMultiState ) {
290         this._checkbox.attr('value',state.mixed ? "mixed" : state.checked ? "checked" : "unchecked" );
291       } else {
292         this._checkbox.attr('value',state.checked ? "checked" : "unchecked" );
293       }
294       this._checkbox.attr('checked',state.checked );
295     } else {  
296       if( this.tree.checkboxMultiState ) {
297         this._checkbox.value = state.mixed ? "mixed" : state.checked ? "checked" : "unchecked";
298       } else {
299         this._checkbox.value = state.checked ? "checked" : "unchecked";
300       }
301       this._checkbox.checked = state.checked;
302     }
303   },

On line 288 we first determine the checkbox style, next we check if multi (mixed) state support is required. On line 297 you can actually see that even if we use the default HTML checkbox we can still support mixed states. In other words, under the hood we support multi state checkboxes regardless of the checkbox style.

Update The Tree

Last but not least we have to make some minor changes to the Tree as well. I already talked about the additional attributes:

317 dojo.declare( "tmpdir.CheckBoxTree", dijit.Tree,
318 {
319   checkboxStyle: "dijit",
320 
321   checkboxMultiState: true,
322 
323   branchIcons: true,
324 
325   nodeIcons: true,

I also talked about the Tree no longer simply updating the checkbox checked state, going forward the _onCheckboxChange method of the Tree will call the _setCheckedState method of the CheckBoxTreeNode to have both states (checked and mixed) updated.

352   _onCheckboxChange: function( storeItem ) {
353 
354     var model  = this.model,
355       state    = model.getCheckboxState( storeItem ),
356       identity = model.getIdentity(storeItem),
357       nodes    = this._itemNodesMap[identity];
358 
359     if( nodes ) {
360       dojo.forEach( nodes, function(node) {
361         if( node._checkbox != null )
362           node._setCheckedState( state );
363       }, this );
364     }
365   },

Well, that's it for our CheckboxTree and extended Checkbox widgets, the only thing left to do is to update our index.html file to include our new CSS file and add some of our new attributes. The new attributes aren't really necessary if you are Ok with their default value. I have included them just to show how to overwrite their default values if needed.

  1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  2       "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
  3 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
  4   <head>
  5     <title>Dijit Tree with Checkboxes </title>
  6     <link rel="stylesheet" href="/js/dojotoolkit/dijit/themes/nihilo/nihilo.css" />
  7     <link rel="stylesheet" href="/js/tmpdir/themes/nihilo/tmpdir.css" />
  8 
  9     <script type="text/javascript" src="/js/dojotoolkit/dojo/dojo.js"
 10         djConfig="parseOnLoad:true, isDebug:false"></script>
 11 
 12     <script type="text/javascript">
 13       dojo.registerModulePath("tmpdir","/js/tmpdir");
 14       dojo.require("dojo.data.ItemFileWriteStore");
 15       dojo.require("tmpdir.CheckBoxTree");
 16 
 17     function myTree( domLocation ) {
 18       var store = new dojo.data.ItemFileWriteStore( {
 19               url: "/js/datastore/Family.json"
 20               });
 21       var model = new tmpdir.CheckBoxStoreModel( {
 22               store: store,
 23               query: {type: 'parent'},
 24               rootLabel: 'The Family',
 25               checkboxAll:  true,
 26               checkboxRoot: true,
 27               checkboxState: true,
 28               checkboxStrict: true
 29               });
 30       var tree = new tmpdir.CheckBoxTree( {
 31               model: model,
 32               id: "MenuTree",
 33               allowMultiState: true,
 34               branchIcons: true,
 35               nodeIcons: true
 36               });
 37       tree.placeAt( domLocation );
 38     }
 39     </script>
 40   </head>
 41 
 42     <body class="nihilo">
 43     <div id="CheckboxTree">
 44       <script type="text/javascript">
 45         myTree("CheckboxTree");
 46       </script>
 47     </div>
 48   </body>
 49 </html>

The only real import change we are making to our index.html file is on line 7, the inclusion of our CSS file. Please make sure the tmpdir theme is the same as the one you select for dijit on line 6.

If the CSS themes do not match you are NOT going to see any checkboxes unless you set the checkboxStyle attribute to anything else but "dijit".

Below you see three different representations of the same Family Tree using some of our configurable attributes. These examples are all using dojo 1.4 to demonstrate the multi parent support. For example: In our Json file Chantal is referenced by both Peter and Mary as a child. In addition, Peter is defined as a 'parent' and but also referenced by John as a child.

Multi State Checkbox Tree Collection

The example on the right uses the default HTML checkboxes BUT, as mentioned before, under the hood it still maintains the mixed state and thus your application can check if any of the parent checkboxes (John, Mary, Peter, Joan and Chantal) are in a mixed state. You can disable the mixed state support by setting the checkboxMultiState to false in which case the value attribute of the checkbox can only be 'checked' or 'unchecked' but not 'mixed'.

To give our new tree a spin, click here for a little demo.

Checkbox Tree Configurable Attributes

Over the course of these two tutorials we have introduced a number of attributes to our CheckBoxTree and CheckBoxStoreModel widgets. The tables below list all attributes, their default value and a short description.

Note: Any attribute that has a default value assigned is considered optional.

CheckBoxStoreModel Attributes

Attribute Type Default Description
checkboxAll Boolean true If true, every node in the tree will receive a checkbox regardless if the attribute 'checkbox' is specified or not for a dojo.data item. If the 'checkbox' attribute is not specified the default value checkboxState will be applied.
checkboxIdent String "checkbox" The name of the attribute (attribute of the dojo.data.item) that specifies the items checkbox initial state.
Example: { name:'Egypt', type:'country', checkbox: true }
If a dojo.data.item has no 'checkbox' attribute specified it will depend on the attribute 'checkboxAll' if one will be created automatically and if so what the initial state will be as specified by 'checkboxState'.
checkboxMState String "mixed" The name of the attribute (attribute of the dojo.data/item) that will hold the checkbox mixed state. The mixed state is separate from the default checked/unchecked state of a checkbox.
checkboxRoot Boolean false If true, the root node will receive a checkbox even though it's not a true entry in the store.
This attribute is independent of the showRoot attribute of the Tree itself. If the Tree attribute 'showRoot' is set to false the checkbox for the root will not show either.
checkboxState Boolean false The default value/state applied to every checkbox unless otherwise specified for the dojo.data item.
(see also: checkboxIdent)
checkboxStrict Boolean true If true, a strict parent-child checkbox relation is maintained. For example, if all children are checked the parent will automatically be checked or if any of the children are unchecked the parent will be unchecked.

CheckBoxTree Attributes

Attribute Type Default Description
branchIcons Boolean true Determines if the FolderOpen/FolderClosed icon is displayed.
checkboxMultiState Boolean true Determines if Multi State (mixed) checkbox behavior is required. If set to false the value property of a checkbox can only be 'checked' or 'unchecked'. If true the value can be 'checked', 'unchecked' or 'mixed'
checkboxStyle String "dijit" Sets the style of the checkbox to be used. The default is "dijit" any other value will force the use of the native HTML style checkbox. The visual representation of a mixed state checkbox is only supported with a dijit style checkbox.
nodeIcons Boolean true Determines if the Leaf icon is displayed.

Other Tree/Model Attributes

Attribute Type Default Description
showRoot Boolean true Determines if the root node should be displayed or hidden.
persist Boolean true Enables/disables the use of cookies for state saving.
autoExpand Boolean false Fully expand the tree on load. Overrides `persist`
rootLabel String "ROOT" Label of the fabricated root item (also see showRoot)