2 Replies Latest reply on Jul 13, 2007 5:43 AM by tomzi

    rich:tree Ever wanted to know if the node you click is a lea

    tomzi

      I wanted to create a rich:modalPanel containing a rich:tree. When I click on a leaf it should close the panel and update the product in an h:outputText field.

      Right now just found out how to make the modalPanel close when I click on a leaf (Product), so I am pretty excited. However, when I click on a node (Product Categorie) it should not close the panel.

      This is how I did it:

      The magic is following line:

      if (!event['treeItem'].hasChilds()) { Richfaces.hideModalPanel('webacform3:panel3') }


      It tells you nowhere in the rich:tree docu how to find out on the client side if you clicked on a leaf or not. So by debugging with FireBug on Firefox I found the .hasChilds method (which should actually be called hasChildren, but here we go).

      The rest of the code is here:

      The css (working, adding a scrollbar when the tree extends the modalpanels fixed size):
       <style type="text/css">
       .dr-mpnl-pnl {overflow:auto!important}
       .rich-mpnl-body { height: 92%; width:99%; padding:0px; }
       .rich-mpnl-body .content { padding: 10px; }
       </style>
      


      The rich:modalpanel containing the rich:tree.

       <a4j:form id="webacform3">
       <a4j:outputPanel ajaxRendered="true">
       <webac:messages />
       </a4j:outputPanel>
      
       <a href="javascript:Richfaces.showModalPanel('webacform3:panel3')">
       <h:outputText id="currentlySelectedProduct"
       value="#{chooseActivation_backing.productTypes.selectedProduct == null ?
       'Select Product' :
       chooseActivation_backing.productTypes.selectedProduct.name}"></h:outputText>
       </a>
      
       <rich:modalPanel id="panel3"
       resizeable="false" moveable="false" height="300"
       width="400">
      
       <f:facet name="header">
       <h:outputText value="Select Product"></h:outputText>
       </f:facet>
       <f:facet name="controls">
       <a
       href="javascript:Richfaces.hideModalPanel('webacform3:panel3')">X</a>
       </f:facet>
       <div class="content" >Please Select a Product: <br />
      
       <rich:tree id="tree" switchType="client"
       value="#{chooseActivation_backing.productTypes.currentProducts}"
       var="data" ajaxSubmitSelection="true"
       reRender="currentlySelectedProduct"
       onselected="if (!event['treeItem'].hasChilds()) { Richfaces.hideModalPanel('webacform3:panel3') }"
       preserveModel="none"
       nodeFace="#{!empty data.subProducts == true ? 'input' : 'text'}"
       immediate="false"
       nodeSelectListener="#{chooseActivation_backing.productTypes.onTreeSelect}">
       <rich:treeNode type="input"
       oncollapse="Element.removeClassName(event['treeItem'].getElement(), 'colored')"
       onexpand="Element.addClassName(event['treeItem'].getElement(), 'colored')">
       <h:outputText value="#{data.name}" />
       </rich:treeNode>
       <rich:treeNode type="text" nodeClass="customNode">
       <h:commandLink value="#{data.name}" />
       </rich:treeNode>
       </rich:tree></div>
      
       </rich:modalPanel>
       </a4j:form>
      
      


      And the ProductsDto class which is referenced in the backingbean chooseActivation_backing

      
      import java.util.List;
      
      import javax.faces.component.UIComponent;
      import javax.faces.event.FacesEvent;
      
      import org.richfaces.component.TreeNode;
      import org.richfaces.component.UITree;
      import org.richfaces.component.UITreeNode;
      import org.richfaces.component.events.NodeSelectedEvent;
      
      import com.bearingpoint.ta.product.add.jsf.TreeNodeBuilder;
      import com.bearingpoint.ta.product.add.model.ConcreteProductBuilder;
      import com.bearingpoint.ta.product.add.model.Product;
      import com.bearingpoint.ta.product.add.model.ProductBuilder;
      
      public class ProductsDto {
      
       private TreeNode currentProducts;
      
       private List<Product> productHirarchie;
      
       private TreeNode selectedNode = null;
      
       public void init()
       {
       createProductTreeComponent();
       }
      
       private UITree getTree(FacesEvent event) {
       UIComponent component = event.getComponent();
       if (component instanceof UITree) {
       return ((UITree) component);
       }
      
       if (component instanceof UITreeNode) {
       return ((UITree) component.getParent());
       }
      
       return null;
       }
      
       public void onTreeSelect(NodeSelectedEvent event) {
       if (getTree(event).getTreeNode()!=null && getTree(event).isLeaf()) {
       this.selectedNode = getTree(event).getTreeNode();
       }
       }
      
      
       private void createProductTreeComponent() {
       currentProducts = new TreeNodeBuilder(productHirarchie).build();
       }
      
       public static ProductBuilder createNewProducts() {
      
       return ConcreteProductBuilder.newProducts();
       }
      
       public void setProductHirarchie(List<Product> productHirarchie) {
       this.productHirarchie = productHirarchie;
       }
      
       public List<Product> getProductHirarchie() {
       return productHirarchie;
       }
      
       public void setCurrentProducts(TreeNode currentProducts) {
       this.currentProducts = currentProducts;
       }
      
       public TreeNode getCurrentProducts() {
       return currentProducts;
       }
      
       public Product getSelectedProduct() {
       return getSelectedNode() == null ? (Product) null : ((Product) getSelectedNode().getData());
       }
      
       public TreeNode getSelectedNode() {
       return selectedNode;
       }
      
      }


      onTreeSelect is called whenever a node in the rich:tree has been selected. This method stores the currently selected node (selectedNode) only if it is a leaf (=Product)
      createProductTreeComponent() only creates a TreeNode tree out of a Product tree, where each node in the TreeNode references to the Product instance (TreeNode.setData()). So the elements referenced via var="data" is actually a Product instance.
      Note that the outputText field also references the selectedNode, so when you selected a leaf, the modalPanel closes and the outputField is being updated.

      I worked quite a while on this - and I just wanted to share my outcome :) Have fun