Problem with rich:tree with added node edit capability
georgespear Apr 7, 2008 6:55 AMI am writing an application using Facelets and RichFaces( currently it's 3.14 but i am planning to move it on 3.20). The idea is to made a tree, populated with vendors, each having nodes with their address information. When user clicks Edit button next to the address node, the values become editable, and instead of Edit button, Save button appears, which when pressed updates address info.
Here is my code:
test.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:a4j="http://richfaces.org/a4j" xmlns:rich="http://richfaces.org/rich"> <a4j:form> <h:outputText value="aaa" /> <rich:panel> <rich:tree style="width:300px" value="#{rootTreeNode.data}" var="item" nodeFace="#{item.type}"> <rich:treeNode type="vendor"> <h:outputText value="#{item.dataObj.vendorName}" /> </rich:treeNode> <rich:treeNode type="addressRoot"> <h:outputText value="Addresses" /> </rich:treeNode> <rich:treeNode type="address"> <table> <tr> <td><a4j:htmlCommandLink value="Edit" action="#{item.startEdit}" /></td> <td><h:outputText value="#{item.dataObj.address}" /></td> <td><h:outputText value="#{item.dataObj.phoneNumber}" /></td> </tr> </table> </rich:treeNode> <rich:treeNode type="address_edit"> <table> <tr> <td><a4j:htmlCommandLink value="Save" action="#{item.endEdit}" /></td> <td><h:inputText value="#{item.dataObj.address}" /></td> <td><h:inputText value="#{item.dataObj.phoneNumber}" /></td> </tr> </table> </rich:treeNode> </rich:tree> </rich:panel> </a4j:form> </ui:composition>
RootTreeNode.java
public class RootTreeNode implements TreeNode{ private Map<Object,TreeNode> childNodes; public void addChild(Object arg0, TreeNode arg1) { this.getChildNodes().put(arg0, arg1); arg1.setParent(this); } public TreeNode getChild(Object arg0) { // TODO Auto-generated method stub return (TreeNode)getChildNodes().get(arg0); } public Iterator getChildren() { // TODO Auto-generated method stub return getChildNodes().entrySet().iterator(); } public Object getData() { // TODO Auto-generated method stub return this; } public TreeNode getParent() { // TODO Auto-generated method stub return null; } public boolean isLeaf() { // TODO Auto-generated method stub return false; } public void removeChild(Object arg0) { getChildNodes().remove(arg0); } public void setData(Object arg0) { // TODO Auto-generated method stub } public void setParent(TreeNode arg0) { // TODO Auto-generated method stub } public Map<Object, TreeNode> getChildNodes() { if (childNodes==null) initData(); return childNodes; } private void initData() { this.childNodes= new LinkedHashMap<Object, TreeNode>(); InitializationBean bean= AppHelper.getObject("appScope"); Map vendorsMap= bean.getVendorsMap(); for (Iterator it=vendorsMap.keySet().iterator(); it.hasNext();) { Object key= it.next(); Vendor vendor=(Vendor)vendorsMap.get(key); TreeNodeImpl<Vendor> vt= new TreeNodeImpl<Vendor>(); TreeNodeImpl<Object> addressesRoot= new TreeNodeImpl<Object>(); addressesRoot.setType("addressRoot"); addressesRoot.setLeaf(false); addressesRoot.setDataObj(null); addressesRoot.setParent(vt); vt.getChildNodes().put(1, addressesRoot); for (Iterator it_at=vendor.getAddress().iterator(); it_at.hasNext();) { Address address= (Address)it_at.next(); Object addr_key=address.getId(); TreeNodeImpl<Address> at= new TreeNodeImpl<Address>(); at.setType("address"); at.setLeaf(true); at.setDataObj(address); at.setParent(addressesRoot); addressesRoot.getChildNodes().put(addr_key, at); } vt.setType("vendor"); vt.setLeaf(false); vt.setDataObj(vendor); vt.setParent(this); childNodes.put(key, vt); } } public void setChildNodes(Map<Object, TreeNode> childNodes) { this.childNodes = childNodes; } public String getType() { return "root"; } }
TreeNodeImpl.java
public class TreeNodeImpl<E> implements TreeNode{ /** * */ private static final long serialVersionUID = 730448288245225451L; private TreeNode parent; private String type; private Map<Object,TreeNode> childNodes; private boolean leaf; private E dataObj; private boolean editMode=false; public boolean isEditMode() { return editMode; } public void setEditMode(boolean editMode) { this.editMode = editMode; if (this.editMode) { this.setType(this.getType()+"_edit"); } else this.setType(this.getType().substring(0, this.getType().length()-5)); } public Map<Object, TreeNode> getChildNodes() { if (childNodes==null) childNodes=new LinkedHashMap<Object, TreeNode>(); return childNodes; } public void setChildNodes(Map<Object, TreeNode> childNodes) { this.childNodes = childNodes; } public E getDataObj() { return dataObj; } public void setDataObj(E dataObj) { this.dataObj = dataObj; } public void addChild(Object arg0, TreeNode arg1) { // TODO Auto-generated method stub } public TreeNode getChild(Object arg0) { // TODO Auto-generated method stub return childNodes.get(arg0); } public Iterator getChildren() { // TODO Auto-generated method stub return getChildNodes().entrySet().iterator(); } public Object getData() { // TODO Auto-generated method stub return this; } public TreeNode getParent() { return parent; } public boolean isLeaf() { // TODO Auto-generated method stub return leaf; } public void removeChild(Object arg0) { // TODO Auto-generated method stub } public void setData(Object arg0) { // TODO Auto-generated method stub } public void setParent(TreeNode arg0) { this.parent=arg0; } public String getType() { return type; } public void setType(String type) { this.type = type; } public void setLeaf(boolean leaf) { this.leaf = leaf; } public String startEdit() { setEditMode(true); return ""; } public String endEdit() { setEditMode(false); return ""; } }
The problem is that when i set debug point on method TreeNodeImpl.endEdit() - this breakpoint never hits! I even changed event on Save button to call the same method that is called by Edit button, that is startEdit(), but it is also never called. Am i missing something? I really need this to work.