开发者

how to associate (bind) a dijit.Menu with specific nodes of a dijit.Tree

I have been able to bind a simple dijit.Menu with two MenuItems to the nodes of a dijit.Tree wtih Menu.bindDomNode(Tree.domNode), but I would like to refine what nodes get the context menu and am having trouble getting domNodes from Tree items to bind the menu to. I am hoping there is a much easier way of doing this?

    datStore = this.DataStore;

    mdl = this.Model;

    tree = this.Tree;

    datStore.fetch({

        query: { nodeType: "ROOT" },
        onItem: function(item, request) {

            dojo.forEach(datStore.getValues(item, "children"), function(childItem) {

  var itemNode = tree.getNodesByItem(mdl.getIdentity(childItem));

  console.log(itemNode): //returns the widget, and the widget has a domNode property that seems ok with firebug traversing of the itemNode object, though the div value is 'dimmed' in firebug (not valid node yet in the DOM?)

                console.log(itemNode.domNode);//returns 'undefined', so the binding below does not work
开发者_JS百科
                if (childItem.nodeType == "MATCHED_VALUE") {

                   Menu.bindDomNode(itemNode.domNode);

                }

            });
        }
    });


You can also use the menu's onFocus event for this, if you don't like using pseudo-private methods like "_openMyself". You should make a right-click change the currently selected node though.

var tree = new dijit.Tree({
    onMouseDown:function(ev,node){
        if(ev.button==2){ // right-click
            var here=dijit.getEnclosingWidget(ev.target);
            this.set('selectedNode',here);
        }
    }
});
var menuItem=new dijit.MenuItem({...});
var myMenu = new dijit.Menu({
    onFocus:function(){
        var selected=tree.selectedItem;
        // do stuff here like:
        menuItem.attr('disabled',(selected.children)?true:false);
    }
});
myMenu.addChild(menuItem);
myMenu.bindDomNode(tree.domNode);

This took me hours of trial and error to find out, due to the notoriously lacking Dojo documentation. That's why I'm posting this here, 2 years after the question.


I have made something like this:

<div dojoType="dijit.Tree" id="tree" model="continentModel" openOnClick="true">
    <script type="dojo/connect">
        var menus = {
            continent : dijit.byId('treeMenuContinent'),
            country : dijit.byId('treeMenuCountry'),
            city : dijit.byId('treeMenuCity')
        };
        this.onOpen = function(item, node){
            function bindProperMenu( node, item ) {
                var m, type;
                item = item || {};
                for(m in menus) {
                    menus[m].unBindDomNode(node);
                }
                type = continentStore.getValue(item, 'type');
                if (type) {
                    menus[type].bindDomNode(node);
                }
            }

            // the store object has a `root 'field
            // for which we do not want to call the menu
            if (!item.root) {
                var children = node.containerNode.childNodes,
                    n = children.length,
                    thisWidget;
                while(n--) {
                    // add the appropriate menu for children
                    thisWidget = dijit.getEnclosingWidget(children[n]);
                    bindProperMenu(thisWidget.domNode, thisWidget.item);
                }
                // attach menu to the current node
                bindProperMenu(node.domNode, item);
            } else {
                // we're on the "Continents" node, add artificially
                menus['continent'].bindDomNode(this.domNode);
            }
        }
    </script>
</div>

Further explanation here. I know it's in polish - sorry :P

In our tree, the node with the "Continents" label does not exist (ie it is not in the data store). There is no item corresponding to this item in the tree. Hence, this hack was needed with a stiff assignment:

menus['continent'].bindDomNode(this.domNode);

Another solution is:

  1. change data store - adding item "Continents"
  2. indication of all continents as children of this item in the data store
  3. adding the showRoot="false" parameter to the tree widget
  4. change in the value model of the attribute query =' {'name': 'Continents'}'

But there are many online demos, eg:

  • http://www.yarpo.pl/download/examples/dojo/tree/menu/dijit.Menu-on-tree-menu2node.html : it works as you want it to
  • http://www.yarpo.pl/download/examples/dojo/tree/menu/dijit.Menu-on-tree-menu2node-hack.html : better solution


Your way looks OK. You could also keep binding to the Tree node itself but override Menu._openMyself(). There's similar code in test_Tree.html:

dojo.connect(menu, "_openMyself", this, function(e){
// get a hold of, and log out, the tree node that was the source of this open event
var tn = dijit.getEnclosingWidget(e.target);
console.debug(tn);

// now inspect the data store item that backs the tree node:
console.debug(tn.item);

// contrived condition: if this tree node doesn't have any children, disable all of the menu items
dojo.forEach(menu.getChildren(), function(i){ i.set('disabled', !tn.item.children); });

// IMPLEMENT CUSTOM MENU BEHAVIOR HERE
});

However, I don't think that's necessarily better than your way.


I believe the problem is;

itemNode.domNode

as `itemNode' is an array, according to documentation: http://dojotoolkit.org/api/1.6/dijit.Tree/getNodesByItem

use: itemNode[0].domNode


Below code shows menu onclick of a tree node

<!DOCTYPE html>
<html >
<head>

<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/dojo/1.7.2/dijit/themes/claro/claro.css" />    
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dijit/themes/tundra/tundra.css" />
 <script src="//ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.js" data-dojo-config="parseOnLoad: true"></script>

<script>require(["dojo/parser", "dojo/store/Memory", "dijit/Menu", "dijit/MenuItem", "dijit/tree/ObjectStoreModel", "dijit/Tree"]);</script>
<script type="text/javascript">
    dojo.require("dojo.data.ItemFileReadStore");
    dojo.require( "dijit.Tree" );
    dojo.require("dijit.Menu");
    dojo.require("dijit.MenuItem");
    dojo.require("dijit.tree.ForestStoreModel");
    dojo.require("dojo.data.ItemFileReadStore");
    dojo.require("dijit.Tree");

    var rawdata = [ {
        label: 'Vegetables',
        id: '1',
        children:  [ { label: 'tomato', id: '1.1' }, { label: 'onion', id: '1.2' } ]
    }, {
        label: 'Fruits',
        id: '2',
        children: [
            { id: '2.1', label: 'Apple' },           
            { id: '2.3', label: 'Grapes' }
        ]
    } ];

    function prepare(){
        var store = new dojo.data.ItemFileReadStore({
            data: { identifier: 'id', label : 'label', items: rawdata }
        });
        var treeModel = new dijit.tree.ForestStoreModel({ store: store });
        var treeControl = new dijit.Tree({
            model: treeModel,
            showRoot: false,
            _createTreeNode: function(/*Object*/ args){
                var tnode = new dijit._TreeNode(args);
                tnode.labelNode.innerHTML = args.label;
                return tnode;
            }
        }, "treeOne" );

        var AllMenu = new dijit.Menu({ style: "display: none;"});
        var menuItem1 = new dijit.MenuItem({
               label: "Add Instance",
               iconClass:"",
               style:"background-color:#4B57FA",
               onClick: function(){ alert('started'); }
           });
        AllMenu.addChild(menuItem1);
        AllMenu.bindDomNode(treeControl.domNode);

    }


    dojo.ready(prepare);
</script>


</head>
<body class="claro">
    <div id="treeOne">  </div>


</body>
</html>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜