rich:tree Ever wanted to know if the node you click is a lea
tomzi Jul 13, 2007 5:18 AMI 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