TreeNode: Problem by selecting nodes programatically

UI Components for JSF
Post Reply
r0d
Posts: 3
Joined: 10 Apr 2017, 10:56

10 Apr 2017, 13:23

Hello,

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:

Image

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>
Class for data information for the tree: Document.java

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>


r0d
Posts: 3
Joined: 10 Apr 2017, 10:56

26 Apr 2017, 12:37


Melloware
Posts: 3717
Joined: 22 Apr 2013, 15:48

26 Apr 2017, 15:15

I have definitely confirmed your issue and thanks for the example project. I was debugging it but I don't know the exact right place to try and fix it. Hopefully one of the PF Core developers who knows more about the inner workings will be able to fix it with your sample.
PrimeFaces Developer | PrimeFaces Extensions Developer
GitHub Profile: https://github.com/melloware
PrimeFaces Elite 13.0.0 / PF Extensions 13.0.0
PrimeReact 9.6.1

r0d
Posts: 3
Joined: 10 Apr 2017, 10:56

27 Apr 2017, 12:27

Melloware wrote:
26 Apr 2017, 15:15
I have definitely confirmed your issue and thanks for the example project. I was debugging it but I don't know the exact right place to try and fix it. Hopefully one of the PF Core developers who knows more about the inner workings will be able to fix it with your sample.
Thank you very much for your answer and confirmation.

I will face my case use in other way, but I wanted to link here the issue for people who could find the same bug in future ;)

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 55 guests