JavaServer Faces – Find component recursively
In my current project I had to implement a jsf validator regarding 2 jsf-components. Unfortunately the validate method of the Validator Interface allows only one component as parameter.
To realise a validator for 2 fields I needed a way to get the value of the second involved component.
Therefore I added the id of the second component as parameter.
<t:inputTextarea id="comp1" ... > <f:validator validatorId="myValidator" /> <f:attribute name="compId" value="comp2" /> </t:inputTextarea> <t:inputTextarea id="comp2" ... />
The idea was to use the method
UIViewRoot.findComponent(clientID)
to get the needed component.
To my surprise, sometimes null was returned, mainly when used in nested DataTables. So I walked through the complete component tree and looked “by hand” for the component … and no surprise – it exists!
To solve this problem (looks like a bug in JSF 1.1) I wrote a recursive variant of the findComponent method. This method walks through the complete JSF component tree searches for the component (via clientId) and returns it.
/** * Traverses the componenttree recursively and * returns the desired component * * @param context * @param comp * @param clientId * @return */ public UIComponent findComponentRecursively(FacesContext context, UIComponent comp, String clientId) { if (clientId.equals(comp.getClientId(context))) { return comp; } else { if (comp.getChildCount() > 0) { for (Iterator it = comp.getChildren().iterator(); it.hasNext();) { UIComponent component = (UIComponent) it.next(); UIComponent res = findComponentRecursively(context, component, clientId); if (res != null) { return res; } } } } return null; }
For performance reasons I use the following method. First it tries to look for the desired component directly and uses the recursive variant as fallback.
/** * This method finds a component in the JSF-Tree by its * complete id. Due to a bug in JSF a component is not * always found by @link UIViewRoot.findComponent. * Therefore findComponentRecursively is called if needed. * * @param context * @param comp * @param clientId * @return */ public UIComponent findComponent(FacesContext context, String clientId) { UIComponent newComp = (UIComponent) context.getViewRoot().findComponent(clientId); if (newComp == null) { newComp = (UIInput) JSFHelper.getInstance().findComponentRecursively(context, context.getViewRoot(), clientId); } return newComp; }
I hope this saves you some time when struggling with the same problem.
Wednesday, 12. November 2008 23:55
There are people who think that JSF is broken, so broken that it cannot be fixed and has to be rewritten. How is your experience?
Friday, 14. November 2008 16:23
I don’t think JSF is broken. It is a framework addressing most of the standard problems. Sure i miss some things, but it is great to develop fast Web Applications – and most problems can be solved – with some effort.
Like all frameworks it addresses some problems and solves them … but nothing more