What event should be used on a p:tree to select a

2020-03-31 05:29发布

问题:

I'm creating a PrimeFaces (5.3) tree with a context menu. Selected nodes should be stored in #{myBean.selectedNode}. When I select a node using the left mouse button the correct node is set. But, when I try to run an action on a node from a context menu, without selecting it first, the correct node isn't set (the setter in my bean is not called).

I'm following the example in the PrimeFaces showcase. As you can see, in the PrimeFaces showcase you are able to immediately right click a node, click "View", and the growl will display the correct node.

Here is my setup:

Bean

It is ViewScoped and there is a private TreeNode selectedNode with getter and setter.

Here are the interesting bits:

public void onNodeSelect(NodeSelectEvent event) {
    MyTreeNode myTreeNode = (MyTreeNode) event.getTreeNode();
    myController.setSelected(myTreeNode.getEntity());
}

public void addChild(String name) {
    MyTreeNode myTreeNode = (MyTreeNode) selectedNode;
    MyTreeNode childNode = myTreeNode.addChild(name);
    myController.setSelected(childNode.getEntity());
    myController.insert();
}

XHTML

<h:form id="mainForm">
    <p:tree value="#{myBean.root}" var="node"
            id="myTree" dynamic="true"
            selectionMode="single" selection="#{myBean.selectedNode}">
        <p:treeNode expandedIcon="ui-icon-folder-open" collapsedIcon="ui-icon-folder-collapsed"
                    type="myType">
            <h:outputText value="#{node}"/>
        </p:treeNode>
        <p:ajax event="select" listener="#{myBean.onNodeSelect}" />
    </p:tree>

    <p:contextMenu for="myTree">
        <p:menuitem action="#{myBean.addChild('new')}"
                    value="Add"
                    process="@this"
                    update=":mainForm:myTree"/>
    </p:contextMenu>
</h:form>

I was able to solve this problem by replacing the PrimeFaces.widget.BaseTree.nodeRightClick function in JavaScript in order to trigger the fireNodeSelectEvent on right click.

PrimeFaces.widget.BaseTree.prototype.nodeRightClick = function(e, a) {
    PrimeFaces.clearSelection();
    if ($(e.target).is(":not(.ui-tree-toggler)")) {
        var d = a.parent(), b = a.hasClass("ui-tree-selectable");
        if (b && this.cfg.selectionMode) {
            var c = this.isNodeSelected(d);
            if (!c) {
                if (this.isCheckboxSelection()) {
                    this.toggleCheckboxNode(d)
                } else {
                    this.unselectAllNodes();
                    // Fixed right click selecting
                    // original code: this.selectNode(d, true)
                    this.selectNode(d); // <-- Fix
                }
            }
            this.fireContextMenuEvent(d)
        }
    }
}

This seemed like a bug to me, so I created an issue on GitHub. This issues was closed as "won't fix" with the comment "Please use contextMenu event".

I've checked the tree and contextMenu section of the documentation twice. What event should be used where? I've asked the same question at GitHub, but there was no response.

回答1:

Reading the issue you reported, I investigated the code (it is open). It seems that p:tree has some undocumented events, contextMenu being one of them (dragdrop being the other).

The 5.3 java-source and 5.3 javascript-source contains references to a contextMenu event, so

<p:ajax event="contextMenu" listener="#{myBean.onContextMenu}" />

and

public void onContextMenu(NodeSelectEvent event) {
    MyTreeNode myTreeNode = (MyTreeNode) event.getTreeNode();
    myController.setSelected(myTreeNode.getEntity());
}

will work. Notice that there is no ContextMenuEvent but that it accepts/needs a NodeSelectEvent