Login Register

How to build a collapsible menu using dijit.Tree

I had a page where I wanted to create a collapsible navigation menu and wanted to learn about the dijit tree widget. I’m pretty happy with the result. Note that I removed the branches and icons associated with the tree to give it a cleaner look. Is this a misuse of the tree widget? Probably, but it does result in a pretty slick menu that is easily maintainable since the hierarchy is stored in a json data file.

The one problem I haven’t been able to overcome is the accessibility issue with the tree. Users that depend on Jaws have problem navigating the menu. To fix this I need to be able to control the tab index for the tree nodes while building the tree as well as tying the enter key with Dojo.connect to methods for collapsing a particular menu (today the arrow keys have to be used).

Find the code for the collapsible menu below. Enjoy!

- note this isn't a complete html file, only the code for adding the tree/menu. Don't for the include the dojo.require("dijit.Tree");

<div id="leftNav">
                <div class="top-level">
                                <div dojoType="dojo.data.ItemFileReadStore" jsId="taskStore"
                                        url="data/tasks.json">
</div>

                                <!-- Dojo code for creating the Navigation tree.  The values
                                found in the tree will be located in the data/task.jsjon.  The
                                ForestStoreModel basically sets up the tree, and the dijit.Tree displays
                                it and associates it with the reidirect to the correct page -->

                                <div dojoType="dijit.tree.ForestStoreModel" jsId="taskModel"
                                        store="taskStore" query="{type:'task'}"
                                        rootId="taskRoot" rootLabel="task" childrenAttrs="children">
</div>

                                <div dojoType="dijit.Tree" id="navigationTree" class="w3tree"
                                        model="taskModel" openOnClick="true" showRoot="false">

                                <script type="dojo/method" event="onClick" args="item">
                                // if the type is subTask we want to redirect the page to the associated link
                                if(taskStore.getValue(item, "type") == "subTask")
                                {
                                        window.location = taskStore.getValue(item, "link");
                                } else if ((taskStore.getValue(item,"type") == "task") && (taskStore.getValue(item,"link") != undefined))
                                {
                                        console.debug("Found a link in a task"+taskStore.getValue(item,"link"));
                                        window.location = taskStore.getValue(item, "link");
                                } else if (taskStore.getValue(item, "newWindow") != undefined)
                                {
                                        console.debug("found a new Window value: "+taskStore.getValue(item, "newWindow"));
                                        window.open(taskStore.getValue(item, "newWindow"));
                                }
                                </script>
                        </div>
                        </div>
                </div>

tasks.json - data file for supplying your two tier menu

{ identifier: 'name',
  label: 'name',
  items: [
         { name:'MyHomePage', type:'task', link:'myHomePage.php' },
     { name:'IDs', type:'task',
         children:
         [
                {_reference:'Show IDs'},
                {_reference:'Create New ID'},
                {_reference:'Delete IDs'},
                {_reference:'Rename IDs'}
         ]
     },
     { name:'Create New ID', type:'subTask', link:'createNewID.php'},
     { name:'Show IDs', type:'subTask', link:'showCurrentIDs.php'},
     { name:'Rename IDs', type:'subTask', link:'renameIDs.php'},
     { name:'Delete IDs', type:'subTask', link:'deleteIDs.php'}
     
     { name:'Passwords', type:'task',
        children:
        [
                {_reference:'Change/Reset Passwords'}
        ]
     },
     { name:'Change/Reset Passwords', type:'subTask', link:'changePasswords.php'}
]}

w3tree.css - the css file to include inorder to create the nice block menu

.w3tree .dijitTreeLabel
{
        margin-left: 0px;
        display: block;
}

/* The top level nodes shoudl have the darker blue background */
.w3tree .dijitTreeIsRoot
{
        background: #99CCFF none repeat scroll 0% 0% !important;
}

/*
 * This should match the top all dijit Tree Labels
 * The > indicates a child selector.  This will only match the top level
 * dijtTreeLabels
 */

.w3tree > .dijitTreeIsRoot > .dijitTreeContainer > .dijitTreeIsRoot
> DIV > .dijitTreeContent >.dijitTreeLabel
{
                padding-left:12px;
}

/* This should only match children Tree Labels */
.w3tree > .dijitTreeIsRoot > .dijitTreeContainer > .dijitTreeIsRoot
> .dijitTreeContainer > .dijitTreeNode > DIV > .dijitTreeContent > .dijitTreeLabel
{
                padding-left:24px;
}

/* light blue for the child nodes*/
.w3tree  .dijitTreeNode
{
        background:#CCE5FF none repeat scroll 0% 0%;
        margin-left: 0px;
}

/* This is included so that the background will be the correct color for the child nodes */
.w3tree .dijitTreeContainer
{
        background:#CCE5FF none repeat scroll 0% 0%;
}

.w3tree .dijitTreeContent
{
        border-top:1px solid #FFFFFF;
        padding-bottom:5px;
        padding-left:0px;
        padding-top:5px;
        min-height:5px;
        min-width:5px;
        margin: 0px;
}

/* for w3 we just want to clear out all of the tree branches
 * so remove all icons
 */

.w3tree .dijitLeaf, .w3tree .dijitFolderClosed, .w3tree .dijitFolderOpened,
.w3tree .dijitTreeExpandoOpened, .w3tree .dijitTreeExpandoClosed,
.w3tree .dijitTreeExpandoLeaf
{
        background: none;
        display: none;
}

.w3tree .dijitTreeIcon, .w3tree .dijitTreeExpando
{
        height: 0px;
        width: 0px;
        display: none;
}

.w3tree .topLevel
{
        background: #99CCFF none repeat scroll 0% 0%;
        padding-left: 12px;
}

.w3tree .secondLevel
{
        background:#CCE5FF none repeat scroll 0% 0%;
        padding-left: 24px;
}

.w3tree .thirdLevel
{
        background:#CCE5FF none repeat scroll 0% 0%;
        padding-left: 36px;
}

.w3tree .dijitTreeLabelFocused
{
        background:#EEEEEE none repeat scroll 0% 0%;
        color:#000000;
        text-decoration:underline;
}

.w3tree .dijitTreeNodeEmphasized {
    background:#EEEEEE none repeat scroll 0% 0%;
        color:#000000;
        text-decoration:underline;
}