For a forms framework in which I like to use JSF as the real UI frontend, I am searching for a way that a parent component gets informed if in a child component the value is changed. The facelet of a basic 'control' looks like this(body/head omitted since no-one can run it anyway without a dozen classes):
<xf:input ref="/my/xpath/value">
<xf:label>Label</xf:label>
</xf:input>
The xf:input
component which I developed, dynamically creates a real ui component (PrimeFaces ones) based on the type of the value that ref="/my/xpath/value"
points to. This real ui component is created in a preRenderView event like is done in this example. It is handled in the following method in the 'parent' control
@Override
public void processEvent(SystemEvent event) throws AbortProcessingException {
FacesContext context = FacesContext.getCurrentInstance();
if (!context.isPostback()) {
control = createControl(context);
//context.getApplication().unsubscribeFromEvent(PostValidateEvent.class, getControl().getClass(), this);
control.subscribeToEvent(PostValidateEvent.class, this);
}
}
The actual controls all have an programmatically added ajax handler added to it, which makes it possible to just process the specific input ('implicit ajax'). Default JSF component validations are normally applied and this all works great.
The issue/challenge is that in this 'wrapper' component I'd like to be informed of value changes after the validation. My first idea was to us the subscribeEvent on the dynamically added control like this:
control.subscribeToEvent(PostValidateEvent.class, this);
The subscribing works, but on the postback, an NPE is thrown in the UIComponent
(Mojarra 2.2.9) because the wrapped
is null in the following method
public boolean isListenerForSource(Object component) {
if (wrapped instanceof SystemEventListener) {
return ((SystemEventListener) wrapped).isListenerForSource(component);
} else {
return instanceClass.isAssignableFrom(component.getClass());
}
}
This might be because the actual component seems to be newly created when the data is submitted en hence the 'subscription' is lost.
Registering on the ViewRoot
does not work since the source of the event is always the ViewRoot
and registering on the Application
is plain wrong.
It might be that I'm looking for a solution in the wrong direction but for now I'm clueless. Keep in mind that I have no direct control over the created ui controls, nor do I want to override their renderers if I can prevent to. So signalling the parent from the child control is not an option to.
Other things I tried:
- Using valueChangeListeners but that did not work either with lots of other problems (including ways to make it extensible)
- Using composite components with binding but that failed including them dynamically, requiring naming containers that conflict with the id's required by the rest of the framework, the positions of labels, hints and alerts in the xhtml and/or resulting dom
- Taghandlers to manipulate the tree when creating them
This all is with Mojarra up to 2.2.9 (did not check newer yet or MyFaces)