I am having some problems with tree nodes (I tried it with Tree and TreeTable and the problem is the same). The problem happens by selecting or unselecting a node programatically. For instance, I have the following tree:
What I want to do is that when I select (unselect) the 2015->A->X node, the 2016->A->X is selected or unselected, too, and viceversa. The same for Y and Z. If for instance, I only select and unselect nodes in the same branch, there are no problems. But if I am selecting/unselecting nodes in 2015 branch, and then I select/unselect some node in 2016 branch, some unexpected strange behaviors could happen.
To develop my use case:
- I used select and unselect p:ajax events and I use the update property to render the form again to see the changes in the tree.
- I used the code showed in this web as sample and I modified it ( https://examples.javacodegeeks.com/ente ... n-example/ ).
- A button to show selected nodes are included in the page (It can be seen that selected nodes from selection property are not updated if the selected property of the node is updated programatically, but that is a minor problem that I think I could solve in the backing).
- I attach my complete code at the end of this post.
To reproduce one of this strange behaviors, you can follow the next steps:
1º/ Select 2015->A->X node
Then, the 2016->A->X node is selected
2º/Select 2015->A->Y node
Then, the 2016->A->Y node is selected
3º/Select 2015->A->Z node
Then, the 2016->A->Z node is selected
Nodes 2015, 2016, 2015->A and 2016-A are selected, too, so all its children are selected.
4º/Unselect 2016->A->Y node
Then, the 2015->A->Y node is unselected, but the 2016->A->Y node is still selected.
If you debug the code, in this step, at the begining of the "onNodeUnselect" method, the selected property of 2016->A->Y is true, and false is expected. In fact, by debuggin, in this moment in the page the checbox is unselected, as expected, but after running the code, it is selected automatically.
I force to update the "selected" property to false in the onNodeUnselect method (and to true in the onNodeSelect method). Then this problem is solved, but if you do next step:
5º/ Unselect 2016->A->X node
Then the 2016->A->X node is unselected, and the 2015->A->Y node is selected!
Other combinations of selecting and unselecting nodes produce strange behaviors, too.
I tried different combinations of updating properties, including partiallySelected property update, but I couldn't fix the problem. If you deb
The server used is apache tomcat 8.0.26 in windows.
Tested in chrome and opera with the same behavior.
The JSF and primefaces versions can be seen in the pom.xml I paste here:
pom.xml
Code: Select all
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javacodegeeks.enterprise.jsf.treeselectionjsf</groupId>
<artifactId>treeselectionjsf</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>mojarra-jsf-impl</artifactId>
<version>2.0.0-b04</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>mojarra-jsf-api</artifactId>
<version>2.0.0-b04</version>
</dependency>
<dependency>
<groupId>com.sun.faces</groupId>
<artifactId>jsf-impl</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>6.0</version>
</dependency>
</dependencies>
</project>
Code: Select all
package com.javacodegeeks.enterprise.jsf.treeselectionjsf;
import java.io.Serializable;
public class Document implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public Document(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
Backing SelectionView.java
Code: Select all
package com.javacodegeeks.enterprise.jsf.treeselectionjsf;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import org.primefaces.event.NodeSelectEvent;
import org.primefaces.event.NodeUnselectEvent;
import org.primefaces.model.CheckboxTreeNode;
import org.primefaces.model.TreeNode;
@ManagedBean(name="treeSelectionView")
@ViewScoped
public class SelectionView implements Serializable {
private TreeNode root;
private CheckboxTreeNode _2015;
private CheckboxTreeNode a2015;
private CheckboxTreeNode xa2015;
private CheckboxTreeNode ya2015;
private CheckboxTreeNode za2015;
private CheckboxTreeNode _2016;
private CheckboxTreeNode a2016;
private CheckboxTreeNode xa2016;
private CheckboxTreeNode ya2016;
private CheckboxTreeNode za2016;
public TreeNode createCheckboxDocuments() {
root = new CheckboxTreeNode(new Document("root"), null);
root.setExpanded(true);
_2015 = new CheckboxTreeNode(new Document("2015"), root);
_2015.setExpanded(true);
_2016 = new CheckboxTreeNode(new Document("2016"), root);
_2016.setExpanded(true);
a2015 = new CheckboxTreeNode(new Document("A"), _2015);
a2015.setExpanded(true);
a2016 = new CheckboxTreeNode(new Document("A"), _2016);
a2016.setExpanded(true);
xa2015 = new CheckboxTreeNode(new Document("X"), a2015);
xa2015.setExpanded(true);
ya2015 = new CheckboxTreeNode(new Document("Y"), a2015);
ya2015.setExpanded(true);
za2015 = new CheckboxTreeNode(new Document("Z"), a2015);
za2015.setExpanded(true);
xa2016 = new CheckboxTreeNode(new Document("X"), a2016);
xa2016.setExpanded(true);
ya2016 = new CheckboxTreeNode(new Document("Y"), a2016);
ya2016.setExpanded(true);
za2016 = new CheckboxTreeNode(new Document("Z"), a2016);
za2016.setExpanded(true);
return root;
}
private TreeNode[] selectedNodes;
@PostConstruct
public void init() {
root = createCheckboxDocuments();
}
public TreeNode getRoot() {
return root;
}
public TreeNode[] getSelectedNodes() {
return selectedNodes;
}
public void setSelectedNodes(TreeNode[] selectedNodes) {
this.selectedNodes = selectedNodes;
}
public void displaySelectedNodes(TreeNode[] nodes) {
if(nodes != null && nodes.length > 0) {
StringBuilder builder = new StringBuilder();
for(TreeNode node : nodes) {
if (node.isLeaf()) {
while(node.getParent() != null) {
builder.append(node.getData()).append("<-");
node = node.getParent();
}
builder.append("<br />");
}
}
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Your choices:", builder.toString());
FacesContext.getCurrentInstance().addMessage(null, message);
}
}
public void onNodeUnselect(NodeUnselectEvent event)
{
TreeNode currentTreeNode = event.getTreeNode();
// currentTreeNode.setSelected(false);
TreeNode parent = currentTreeNode;
while (!((Document) parent.getParent().getData()).getName().equals(((Document) root.getData()).getName()))
{
parent = parent.getParent();
//Selects node "2015" or "2016"
}
updateBrother(((Document) currentTreeNode.getData()).getName(), ((Document) parent.getData()).getName(), false);
}
private void updateBrother(String name, String parentName, boolean value)
{
if (parentName.equals("2015"))
{
if (name.equals("2015"))
{
a2015.setSelected(value);
xa2015.setSelected(value);
ya2015.setSelected(value);
za2015.setSelected(value);
_2016.setSelected(value);
a2016.setSelected(value);
xa2016.setSelected(value);
ya2016.setSelected(value);
za2016.setSelected(value);
} else if (name.equals("A"))
{
xa2015.setSelected(value);
ya2015.setSelected(value);
za2015.setSelected(value);
a2016.setSelected(value);
xa2016.setSelected(value);
ya2016.setSelected(value);
za2016.setSelected(value);
} else if (name.equals("X"))
{
xa2016.setSelected(value);
} else if (name.equals("Y"))
{
ya2016.setSelected(value);
}else if (name.equals("Z"))
{
za2016.setSelected(value);
}
} else {
if (name.equals("2016"))
{
a2016.setSelected(value);
xa2016.setSelected(value);
ya2016.setSelected(value);
za2016.setSelected(value);
_2015.setSelected(value);
a2015.setSelected(value);
xa2015.setSelected(value);
ya2015.setSelected(value);
za2015.setSelected(value);
} else if (name.equals("A"))
{
xa2016.setSelected(value);
ya2016.setSelected(value);
za2016.setSelected(value);
a2015.setSelected(value);
xa2015.setSelected(value);
ya2015.setSelected(value);
za2015.setSelected(value);
} else if (name.equals("X"))
{
xa2015.setSelected(value);
} else if (name.equals("Y"))
{
ya2015.setSelected(value);
}else if (name.equals("Z"))
{
za2015.setSelected(value);
}
}
}
public void onNodeSelect(NodeSelectEvent event)
{
TreeNode currentTreeNode = event.getTreeNode();
// currentTreeNode.setSelected(true);
TreeNode parent = currentTreeNode;
while (!((Document) parent.getParent().getData()).getName().equals(((Document) root.getData()).getName()))
{
parent = parent.getParent();
}
updateBrother(((Document) currentTreeNode.getData()).getName(), ((Document) parent.getData()).getName(), true);
}
}
index.xhtml
Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui">
<h:head>
<title>JSF Tree Selection Example</title>
</h:head>
<h:body>
<h:form id="tree">
<p:growl id="msgs" showDetail="true" escape="false"/>
<h3>JSF 2.0 Tree Selection Example</h3>
<p:tree value="#{treeSelectionView.root}" var="doc"
selectionMode="checkbox"
selection="#{treeSelectionView.selectedNodes}"
dynamic="true">
<p:treeNode>
<h:outputText value="#{doc.name}" />
</p:treeNode>
<p:ajax event="select"
listener="#{treeSelectionView.onNodeSelect}"
update=":tree"
/>
<p:ajax event="unselect"
listener="#{treeSelectionView.onNodeUnselect}"
update=":tree"
/>
</p:tree>
<br/>
<p:commandButton value="Show selected" update="msgs" icon="ui-icon-newwin"
actionListener="#{treeSelectionView.displaySelectedNodes(treeSelectionView.selectedNodes)}"/>
</h:form>
</h:body>
</html>