Primefaces 为什么';p:ajax更新&x27;更新p:树失败?

Primefaces 为什么';p:ajax更新&x27;更新p:树失败?,primefaces,Primefaces,我想产生这样的结果,即每当树节点展开时,之前展开的任何同级节点都会折叠 下面是我的页面和我的bean。展开节点时调用onNodeExpanded方法;System.out语句生成预期结果。但是,执行setExpanded(false)的节点在页面上保持展开状态 我添加了一个commandButton,以便强制更新树。按下该键将在页面中正确显示之前由ajax事件侦听器折叠的节点 页面: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transiti

我想产生这样的结果,即每当树节点展开时,之前展开的任何同级节点都会折叠

下面是我的页面和我的bean。展开节点时调用onNodeExpanded方法;System.out语句生成预期结果。但是,执行setExpanded(false)的节点在页面上保持展开状态

我添加了一个commandButton,以便强制更新树。按下该键将在页面中正确显示之前由ajax事件侦听器折叠的节点

页面:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:p="http://primefaces.org/ui">

    <h:head>
        <title>PrimeFaces Tree: Ajax Update Problem</title>
    </h:head>
    <h:body> 
        <h3>PrimeFaces Tree: Ajax Update Problem</h3>

        <h:form>
            <p:tree id="tree" value="#{problemController.root}" var="node" dynamic="true" orientation="horizontal">
                <p:treeNode>
                    <h:outputText value="#{node}" />
                </p:treeNode>

                <p:ajax event="expand" listener="#{problemController.onNodeExpanded}" update="tree" />
            </p:tree>

            <h:commandButton value="Update" immediate="true">
                <f:ajax render="tree" />
            </h:commandButton>
        </h:form>
    </h:body>
</html>
import java.io.Serializable;

import javax.annotation.PostConstruct;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

import org.primefaces.event.NodeExpandEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;

@Named
@ViewScoped
public class ProblemController implements Serializable {

    private static final long serialVersionUID = 1L;
    private TreeNode root;

    @PostConstruct
    public void init() {
        root = new DefaultTreeNode("Root", null);
        TreeNode node0 = new DefaultTreeNode("Node 0", root);
        TreeNode node1 = new DefaultTreeNode("Node 1", root);

        TreeNode node00 = new DefaultTreeNode("Node 0.0", node0);
        TreeNode node01 = new DefaultTreeNode("Node 0.1", node0);

        TreeNode node10 = new DefaultTreeNode("Node 1.0", node1);

        node1.getChildren().add(new DefaultTreeNode("Node 1.1"));
        node00.getChildren().add(new DefaultTreeNode("Node 0.0.0"));
        node00.getChildren().add(new DefaultTreeNode("Node 0.0.1"));
        node01.getChildren().add(new DefaultTreeNode("Node 0.1.0"));
        node10.getChildren().add(new DefaultTreeNode("Node 1.0.0"));
        root.getChildren().add(new DefaultTreeNode("Node 2"));
    }

    public TreeNode getRoot() {
        return root;
    }

    public void onNodeExpanded(NodeExpandEvent event) {
        TreeNode expandedNode = event.getTreeNode();
        System.out.printf("Expanded %s\n", expandedNode);

        TreeNode parent = expandedNode.getParent();
        if (parent != null) {
            for (TreeNode sibling : parent.getChildren()) {
                if (sibling.isExpanded() && sibling != expandedNode) {
                    sibling.setExpanded(false);
                    System.out.printf("Collapsed %s\n", sibling);
                }
            }
        }
    }
}
Java 1.8 PrimeFaces 6.1 Mojarra 2.3 Weld 3.0

更新1

我已经用@Kukeltje提供的代码更新了页面。不幸的是,扩展节点的兄弟节点没有被折叠。我在closeOthers函数中添加了一条语句,该语句记录到控制台:显示我展开的任何节点的数据(“root”或“0”或“0_1”,等等)(如预期的那样)


素数面树
素数面树
//

从组件本身内部的ajax调用中更新完整组件并不常见。由于您使用了
dynamic=“true”
,因此与不使用
dynamic=“true”
相比,您看到的负面影响更少。如果更新
p:tree
周围的容器,也会发生同样的情况。实际上,树上有两个相互冲突的更新,特别是当试图隐藏节点时

实际上,您似乎试图通过使用服务器端的树操作(这本身并没有错),一次只打开一个节点。这确实与中尝试的内容有关,但这个问题的表述过于狭隘,因为它不是关于选择/取消选择或隐藏/取消隐藏,而是更一般的问题,即无法从组件中的ajax调用中更新完整的树组件

仍应在服务器端更新内容,以便仍支持完全刷新。但是,您可以尝试使用
oncomplete
javascript回调关闭客户端的所有其他节点,而不是执行
update=“tree”

添加以下javascript将为您做到这一点:

<h:outputScript>

//<![CDATA[

function closeOthers(current, widget) {

    var dataRowkey = $.urlParam(decodeURIComponent(current.data),current.source+"_expandNode");


    //For a vertical tree:      
    //var selector = "li[data-rowkey='"+dataRowkey+"']";
    //$(widget.jq).find(selector).siblings().find("span[aria-expanded='true']").siblings(".ui-tree-toggler").trigger("click");


    //For a horizontal tree
    var selector = "td[data-rowkey='"+dataRowkey+"']";

    // The first attempt was to look for aria-expanded=true but we
    // found that sometimes it would be present on a collapsed node (bug?).
    // $(widget.jq).find(selector).parent().parent().parent().siblings().find("td[aria-expanded='true']").find(".ui-tree-toggler").trigger("click");

    // Searching instead for the minus icon did the trick
    $(widget.jq).find(selector).parent().parent().parent().siblings().find(".ui-icon-minus").trigger("click");

}


 $.urlParam = function (query, name) {
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(query);
    return (results !== null) ? results[1] || 0 : false;
 }

//]]>
</h:outputScript>

很可能您没有将节点的状态保存到某个地方,而只是再次完全呈现(例如bean的范围)?请学习在发布问题时如何创建问题列表。这使我们在尝试帮助时变得更加容易,因为我们不必开始猜测或提问,或者……有任何进展吗?@Kukeltje我用一个MCV示例更新了这个问题。谢谢你的帮助。我找到了原因/解释。将在今晚或明天写一个答案。太棒了!老兄,我正在考虑为树组件制作一个“补丁”,这样你就可以配置一个“始终打开的单个节点”,使它成为组件的一部分!
<h:outputScript>

//<![CDATA[

function closeOthers(current, widget) {

    var dataRowkey = $.urlParam(decodeURIComponent(current.data),current.source+"_expandNode");


    //For a vertical tree:      
    //var selector = "li[data-rowkey='"+dataRowkey+"']";
    //$(widget.jq).find(selector).siblings().find("span[aria-expanded='true']").siblings(".ui-tree-toggler").trigger("click");


    //For a horizontal tree
    var selector = "td[data-rowkey='"+dataRowkey+"']";

    // The first attempt was to look for aria-expanded=true but we
    // found that sometimes it would be present on a collapsed node (bug?).
    // $(widget.jq).find(selector).parent().parent().parent().siblings().find("td[aria-expanded='true']").find(".ui-tree-toggler").trigger("click");

    // Searching instead for the minus icon did the trick
    $(widget.jq).find(selector).parent().parent().parent().siblings().find(".ui-icon-minus").trigger("click");

}


 $.urlParam = function (query, name) {
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(query);
    return (results !== null) ? results[1] || 0 : false;
 }

//]]>
</h:outputScript>
<p:tree id="tree" widgetVar="treeW" value="#{problemController.root}" var="node" orientation="horizontal">
    <p:treeNode>
        <h:outputText value="#{node}" />
    </p:treeNode>

    <p:ajax event="expand" listener="#{problemController.onNodeExpanded}" oncomplete="closeOthers(this, PF('treeW'))"/>
</p:tree>