我希望产生这样的结果:每当展开树节点时,任何先前展开的兄弟节点都会被折叠。
以下是我的页面和我的bean。扩展节点时调用onNodeExpanded方法; System.out语句产生预期的结果。但是,执行setExpanded(false)的节点仍然在页面上展开。
我添加了一个commandButton,以便我可以强制更新树。按下它会导致页面正确显示先前由ajax事件侦听器折叠的节点。
Page:
<!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>
The Bean:
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”等)(如预期的那样)。
<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</title>
</h:head>
<h:body>
<h3>PrimeFaces Tree</h3>
<h:form>
<p:tree id="tree" widgetVar="treeW" value="#{testController.root}" var="node" orientation="horizontal" selectionMode="single">
<p:treeNode>
<h:outputText value="#{node}" />
</p:treeNode>
<p:ajax event="expand" listener="#{testController.onNodeExpanded}" oncomplete="closeOthers(this, PF('treeW'))"/>
</p:tree>
<h:outputScript>
//<![CDATA[
function closeOthers(current, widget) {
var dataRowkey = $.urlParam(decodeURIComponent(current.data),current.source+"_expandNode");
var selector = "li[data-rowkey='"+dataRowkey+"']";
console.log("Collapsing siblings of " + selector);
$(widget.jq).find(selector).siblings().find("span[aria-expanded='true']").siblings(".ui-tree-toggler").trigger("click");
}
$.urlParam = function (query, name) {
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(query);
return (results !== null) ? results[1] || 0 : false;
}
//]]>
</h:outputScript>
<h:commandButton value="Update" immediate="true">
<f:ajax render="tree" />
</h:commandButton>
</h:form>
</h:body>
</html>
答案 0 :(得分:1)
从组件内部的ajax调用中更新完整组件并不常见。由于您使用dynamic="true"
,因此与不使用dynamic="true"
相比,您看到的下行影响更小。如果您更新p:tree
周围的容器,也会发生同样的情况。树上实际上有2个更新,彼此之间存在冲突,特别是当有一些额外的节点隐藏时。
您实际上似乎想要实现的是通过使用树的服务器端操作(这本身没有错误)一次只打开一个节点。这确实与https://github.com/primefaces/primefaces/issues/2277中所尝试的内容有关,但该问题的制定过于狭窄,因为它不是关于选择/取消选择或者您喜欢隐藏/取消隐藏,而是更普遍的问题,即无法更新组件中ajax调用中的完整树组件。
更新服务器端的东西,以便仍然支持完全刷新仍应该完成。但是,您可以尝试使用update="tree"
javascript回调来关闭客户端的所有其他节点,而不是执行oncomplete
。
添加以下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>
然后
widgetVar="treeW"
p:ajax
中添加一个oncomplete,如此oncomplete="closeOthers(this, PF('treeW'))"
dynamic="true"
或ADD cache="false"
(我发现错误,然后每个节点只能运行一次,https://github.com/primefaces/primefaces/issues/3668 )update="tree"
所以html最终会像:
<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>