I need to add a component (UIParameter) to a HtmlCommandLink component dinamically through a Phase Listener.
What I want to achieve is that every element <h:link outcome="out"> renders as <a href="out_url_parsed + ?param=paramvalue">.Where "param" is my component.
I've tried using this
private void addElement(final PhaseEvent event, final Class clazz, final UIComponent component) {
final FacesContext fcontext = event.getFacesContext();
UIViewRoot root = fcontext.getViewRoot();
if (root == null) {
return;
}
root.visitTree(new FullVisitContext(fcontext), new VisitCallback() {
@Override
public VisitResult visit(VisitContext context, UIComponent target) {
if (clazz.isInstance(target)) {
LOGGER.info("Element Found");
UIParameter parameter = new UIParameter();
parameter.setValue("willberonadom");
parameter.setId("sessiontoken");
target.getChildren().add(parameter);
}
return VisitResult.ACCEPT;
}
});
}
But it's not working. The element is actually found on the tree but the UIParameter does not render.
I've found that the UIViewRoot only has child elements after RENDER_RESPONSE phase. So i think this is why my added element is not rendered at the end of the process.
I'm sure I can add this param editing the views but I don't want to do that since it must be present on all h:link in the application and must be present on any other new added too. So I consider this as a better approach to avoid missing tags
On a similar case I've managed to add input hidden elements to every form on view with this code...
HtmlInputHidden hiddenToken = new HtmlInputHidden();
hiddenToken.setId("sessiontoken");
hiddenToken.setValue("willberandom");
hiddenToken.setRendered(true);
root.addComponentResource(event.getFacesContext(), hiddenToken,"form");
But it doesn't work on anchor tags
There are several mistakes:
You want to add a parameter to a
HtmlCommandLinkcomponent which represents<h:commandLink>, but you're giving an example with<h:link>, which is represented byHtmlOutcomeTargetLink. What exactly do you want?A
PhaseListeneronbeforePhase()ofRENDER_RESPONSEmay be too late on GET requests which would only build the view for the first time during render response. At the moment yourPhaseListenerruns, theUIViewRootwould have no children at all. You'd better hook on view build time instead. For that, aSystemEventListeneronPostAddToViewEventis the best suitable.You're setting the parameter name as an
idinstead ofname. UseUIParameter#setName()instead ofUIParameter#setId().Provided that you actually meant to add them to
<h:link>components, then here's a kickoff example how you can achieve that with aSystemEventListener.(if you actually want to apply them on
<h:commandLink>as well, just extend theisListenerForSource()check with a|| source instanceof HtmlCommandLink)In order to get it to run, register it as follows in
faces-config.xml: