Dijit Tree with Multi State Checkboxes 1.7

Note: This article has been superceded by the The new Dijit CheckBox Tree. The interim 1.7 release referred to in this post is therefore no longer available for download.

More than 2 years after I posted the first version of the dijit tree with multi state checkboxes for dojo 1.4,  and after 20,000+ downloads it was time to get an updated version out.

Actually, it wasn’t until dojo 1.6/1.7 was released that I started to get feedback that the old version wasn’t working properly any more.

Well friends, the 1.7 tree is here with full support for the claro theme and I believe some nice additions. See the picture below.

Tree - claro

Issues reported

The issues reported using the Dijit Multi State Checkbox Tree version 1.4 with dojo 1.6/1.7 can be summarized as follows:

  1. Updates to checkboxes could not be seen until one would hover over the checkbox.
  2. The properties ‘branchIcons’ and ‘nodeIcons’ no longer worked.
  3. No support for the dojo 1.5 claro theme.
  4. Firebug reported the use of deprecated functions.

I’m happy to report, all of the issues have been resolved.

In addition, some people asked if there was any easy way to change the checkbox state programmatically. But then again, others asked if I could write their entire application using my dijit tree because they liked it so much.

I will follow this blog up with a more detailed explanation of the changes required to get everything working again for dojo 1.7. Most of the time went actually into setting up my environment again, you known, getting the latest and greatest version of every tool and then getting everything to work again. All-in-all it took about a day to get every updated and back to normal again. But here is just an excerpt of some of the reasons causing the problems:

As it appears the dojo team had decided to adopt the new AMD technology which stands for Asynchronous Module Definition. Starting with dojo 1,6 an entire refactoring was kicked off which, as far as I understand, should lead to the new and improved dojo 2.0 platform. The implementation of AMD introduced new language structures and as a result of the refactoring new feature were added and of course others got dropped or some behavior slightly changed.

If you are interested in reading more about AMD, and who isn’t right? checkout the following sites:

http://dojotoolkit.org/blog/learn-more-about-amd

https://github.com/amdjs/amdjs-api/wiki/AMD

A good exercise to see how well your code holds up in relation to dojo 1.6/1.7 is to download the latest version of firebug (still the best javascript tool available, don’t leave home without it) and run dojo 1.7 in debug mode. Most likely you will get some warnings regarding the use of deprecated methods/functions.

What’s new in the 1.7 Checkbox Tree

As mentioned before, some people asked if there was an easy way to change the checkboxes programmatically. Well, if you are into dojo everything is simple, just do a fetch() on the model store and call the updateCheckbox() method for each store item with its new state.

Ok, to make is even simpler, version 1.7 has two new methods called check() and uncheck() which allow you to do just that. Both methods take three arguments:

  1. Query
  2. Callback
  3. Scope

The query argument can be either a string or query object. The optional callback argument is a function which is called on completion with the number of store items that matched the query and the number of store items that matched the query and actually changed state. Finally, the optional scope argument specifies the context in which the callback function is to be executed. The release notes have several sample of the new methods. As an example:

myTree.model.check( { name: "John" }, notifyMe, this );

The store will be queried for every item whos name property equals “John” and if the associated checkbox is unchecked it will get checked. How easy is that…

In addition, a new property was added to the tree model which allows to make checkboxes associated with branches read-only.

Download the latest version

The latest AMD version of the Dijit Tree with Multi State Checkboxes can be downloaded here.

And for those who are wondering: “will the 1.7 tree work with dojo 1.6” the answer is: NO, a quick test reveiled that the new language structures required for AMD support are not available in 1.6.

12 Replies to “Dijit Tree with Multi State Checkboxes 1.7”

  1. Thanks for this update. Works exactly as described. I’ve replaced a modified version of previous 1.4 release that I’d hacked to work with 1.7. Fixes all my issues.
    Again great documentation.

    As a supplementary – How can this become part of the standard Dojo release code?

    1. The author would need a ICLA on file with the Dojo Foundation, and the dijit BDFL (Bill Keese) would have to approve the code before it would be considered for Dijit…

      For anything to be in Dijit it must be fully A11y and i18n supported to meet our standards. Also with the new AMD code (and planned move to github) a communities package manager (CPM) similiar to nodes NPM is being added to allow for easy publishing of 3rd party modules.

      Contributing to Dojo Toolkit is covered here: http://dojotoolkit.org/get-involved

  2. Hi,

    On your demo page, the checkboxes are not appearing in Chrome or Safari for Mac. In the console there is a “undefined is not a function” error on line 78 of the webpage.

    Regards,
    Guy

    1. @guy

      I’m in the middle of updating the server to get it ready for the release of the AMD version of the CheckBox Tree. Unfortunately in doing some parts of the old demo got deleted. In the mean time you can give the new demo a try.

    1. Yes you can however, first make sure you have downloaded the latest AMD version of the CheckBox Tree. The new AMD version of the CheckBox Tree comes with a simple to use store model API.
      Instead of onChange I would recommend using onCheckBoxClicked instead as the onChange event is generated for any update to the underlying store, not just the checked state of a checkbox.
      Now try something like:

      
      require([
        "dojo/_base/array",
        "dojo/_base/connect",
        "dojo/data/ItemFileWriteStore",
        "cbtree/Tree",
        "cbtree/models/ForestStoreModel",
        "cbtree/models/StoreModel-API"    // Load store model API
        ], function( array, connect, ItemFileWriteStore, Tree, ForestStoreModel,
                     StoreModelAPI ) {
      
          function checkBoxClicked( item, nodeWidget, evt ) {
            // Get all store items with a checked state AND whose checked
            // state equals true.
            this.fetchItemsWithChecked( {"checked": true}, function (checkedItems) {
                array.forEach( checkedItems, function (item) {
                    console.log( "Item: " + this.getLabel( item ) + " is checked" );
                  }, this 
                );
              }, this );
          }
      
          var store = new ItemFileWriteStore( { url: "/js/datastore/Simpsons.json" });
          var model = new ForestStoreModel( { store: store, 
                                              query: {type:'parent'},
                                              rootLabel: 'The Family'}); 
          var tree  = new Tree( { model: model, id: "mYTree" });
          tree.placeAt( "CheckboxTree" );
      
          connect.connect( tree, "onCheckBoxClick", model, checkBoxClicked );
      });
      

      Hope this works for you.

  3. I have a JS variable whose value is JSON object(a string),so I just wonder if I can use this JSON string in the html page to create a tree , I found most of sample code is to use ItemFileWriteStore, can we use other store to create a tree based on a JSON string JS variable ? how the sample code looks like ? Thanks for your comments in advance.

    1. You can use the ItemFileWriteStore but instead of using the url property use the data property to pass an JSON encoded string. The following code sample demonstrates the use of an in memory JSON object instead of an URL.

      
      require([
         "dojo/data/ItemFileWriteStore",
         "cbtree/Tree",                    // Checkbox tree
         "cbtree/models/ForestStoreModel"  // ForestStoreModel
         ], function( ItemFileWriteStore, Tree, ForestStoreModel) {
              // Declare an JSON object
              var data = { "identifier": "name", 
                           "label": "name",  
                           "items": [
                             { "name":"Australia", "type":"continent", "children":
                               { "name":"Commonwealth of Australia", "type":"country"}
                               },
                             { "name":"Europe", "type":"continent", "children":[
                               { "name":"Germany", "type":"country" },
                               { "name":"France", "type":"country" },
                               { "name":"Spain", "type":"country" },
                               { "name":"Italy", "type":"country" } ]
                             },
                             { "name":"North America", "type":"continent", "children":[
                               { "name":"Mexico", "type":"country", "children":[
                                 { "name":"Mexico City", "type":"city" },
                                 { "name":"Guadalajara", "type":"city" } ]
                               },
                               { "name":"Canada", "type":"country", "children":[
                                 { "name":"Ottawa", "type":"city"},
                                 { "name":"Toronto", "type":"city"}]
                               },
                               { "name":"United States of America", "type":"country" } ]
                             }
                          ]
                        };
      
              var store = new ItemFileWriteStore( { data: data });
              var model = new ForestStoreModel( { store: store, 
                                                  query: {type: "continent"}, 
                                                  rootLabel: "The Earth" 
                                                }); 
              var tree = new Tree( { model: model, id: "earthTree" });
              tree.placeAt( "CheckboxTree" );
              tree.startup();
          });
      

      Please note that this sample is based on the AMD version of the CheckBox Tree. Make sure you have downloaded the latest version of the CheckBox Tree.

      I hope this helps.

      1. Thanks for your comments,
        Can we add this tree components declaratively. for example , we have a JSON Javascript object ,
        // Declare an JSON object
        var dataObj = { “identifier”: “name”,
        “label”: “name”,
        “items”: [
        { “name”:”Australia”, “type”:”continent”, “children”:
        { “name”:”Commonwealth of Australia”, “type”:”country”}
        },
        { “name”:”Europe”, “type”:”continent”, “children”:[
        { “name”:”Germany”, “type”:”country” },
        { “name”:”France”, “type”:”country” },
        { “name”:”Spain”, “type”:”country” },
        { “name”:”Italy”, “type”:”country” } ]
        },
        { “name”:”North America”, “type”:”continent”, “children”:[
        { “name”:”Mexico”, “type”:”country”, “children”:[
        { “name”:”Mexico City”, “type”:”city” },
        { “name”:”Guadalajara”, “type”:”city” } ]
        },
        { “name”:”Canada”, “type”:”country”, “children”:[
        { “name”:”Ottawa”, “type”:”city”},
        { “name”:”Toronto”, “type”:”city”}]
        },
        { “name”:”United States of America”, “type”:”country” } ]
        }
        ]
        };

        then we will use this JS variable to add the tree components declaratively, the following code line is to use url to link to a json file , but if we want to use above JS dataObj variable whose
        is the JSON object, what we need to change for the following code line to swtich from the url to the JSON object(the variable is dataObj)

        1. Before I show how it would be done you have to understand a couple of things.
          The CheckBox Tree (cbtree) is fully AMD compliant and creates anonymous classes. Dojo 1.7 does NOT support declarative creation of such anonymous classes. Dojo 1.8 will but has not been released yet, there is a Dojo 1.8 “release candidate” available. However, because of the changes made in Dojo 1.8 you would also need a 1.8 version of the CheckBox Tree which I haven’t released yet either.

          I think Dojo 1.8 will be release in the next couple of weeks. As soon as it is available I will also release the updated CheckBox Tree for Dojo 1.8

          Having said that here is how your code could like this: (I’ve tested it on dojo 1.8rc).

          
          <!DOCTYPE html>
          <html>
            <head> 
              <meta charset="utf-8">
              <title>Dijit Tree with Checkboxes </title>     
              <style type="text/css">
                @import "../../dijit/themes/claro/claro.css";
                @import "../themes/claro/claro.css";
              </style>
          
              <script type="text/javascript">
                var dojoConfig = {
                      async: true,
                      parseOnLoad: true,
                      isDebug: true,
                      baseUrl: "../../",
                      packages: [
                        { name: "dojo",  location: "dojo" },
                        { name: "dijit", location: "dijit" },
                        { name: "cbtree",location: "cbtree" }
                      ]
                };
          
                var data = { "identifier": "name", 
                             "label": "name",  
                             "items": [
                                { "name":"Africa", "type":"continent", "children":[
                                  { "name":"Egypt", "type":"country" },
                                  { "name":"Kenya", "type":"country", "children":[
                                    { "name":"Nairobi", "type":"city" },
                                    { "name":"Mombasa", "type":"city" } ]
                                  },
                                  { "name":"Sudan", "type":"country", "children":
                                    { "name":"Khartoum", "type":"city" }
                                  } ]
                                },
                                { "name":"Asia", "type":"continent", "children":[
                                  { "name":"China", "type":"country" },
                                  { "name":"India", "type":"country" },
                                  { "name":"Russia", "type":"country" },
                                  { "name":"Mongolia", "type":"country" } ]
                                },
                                { "name":"Australia", "type":"continent", "children":
                                  { "name":"Commonwealth of Australia", "type":"country"}
                                },
                                { "name":"Europe", "type":"continent", "children":[
                                  { "name":"Germany", "type":"country" },
                                  { "name":"France", "type":"country" },
                                  { "name":"Spain", "type":"country" },
                                  { "name":"Italy", "type":"country" } ]
                                },
                                { "name":"North America", "type":"continent", "children":[
                                  { "name":"Mexico", "type":"country", "children":[
                                    { "name":"Mexico City", "type":"city" },
                                    { "name":"Guadalajara", "type":"city" } ]
                                  },
                                  { "name":"Canada", "type":"country", "children":[
                                    { "name":"Ottawa", "type":"city"},
                                    { "name":"Toronto", "type":"city"}]
                                  },
                                  { "name":"United States of America", "type":"country" } ]
                                },
                                { "name":"South America", "type":"continent", "children":[
                                  { "name":"Brazil", "type":"country" },
                                  { "name":"Argentina", "type":"country" } ]
                                }
                            ]
                          };
              </script>
          
              <script type="text/javascript" src="../../dojo/dojo.js"></script> 
              <script type="text/javascript">
                require([
                  "dojo/data/ItemFileWriteStore",
                  "dojo/parser",
                  "cbtree/Tree",                    // Checkbox tree
                  "cbtree/models/ForestStoreModel"  // ForestStoreModel
                  ]);
              </script>
            </head>
              
            <body class="claro">
              <h1 class="DemoTitle">Dijit Tree with Multi State CheckBoxes</h1>
              A basic CheckBox Tree using an in memory JSON object to create the store.
              <div data-dojo-id="myStore" data-dojo-type="dojo/data/ItemFileWriteStore" data-dojo-props='data:data'></div>
              <div data-dojo-id="myModel" data-dojo-type="cbtree/models/ForestStoreModel" data-dojo-props='store:myStore, query:{type:"continent"}, rootLabel:"Continents"'></div>
              <div id="myTree" data-dojo-type="cbtree/Tree" data-dojo-props='model:myModel'></div> 
            </body> 
          </html>
          

          If you really have to do things declarative at least you have a working sample when dojo 1.8 and the CheckBox Tree 1.8 are released 🙂

          Good luck.

Leave a Reply

Your email address will not be published. Required fields are marked *