对于我喜欢使用JSF作为真正的UI前端的表单框架,我正在寻找一种方法,如果在子组件中值被更改,则父组件会被通知。一个基本的控件的面孔'看起来像这样(身体/头部省略,因为没有人可以在没有十几个课程的情况下运行它):
<xf:input ref="/my/xpath/value">
<xf:label>Label</xf:label>
</xf:input>
我开发的xf:input
组件根据ref="/my/xpath/value"
指向的值的类型动态创建一个真实的ui组件(PrimeFaces组件)。这个真正的ui组件是在preRenderView事件中创建的,就像在这个例子中完成的那样。它通过以下方法在父母的“父母”中进行处理。控制
@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);
}
}
实际的控件都添加了一个以编程方式添加的ajax处理程序,这样就可以只处理特定的输入(&#39;隐式的ajax&#39;)。通常应用默认的JSF组件验证,这一切都很有效。
问题/挑战在于这个&#39;包装器&#39;组件I希望在验证后被告知价值变化。我的第一个想法是向我们发送动态添加控件的subscribeEvent,如下所示:
control.subscribeToEvent(PostValidateEvent.class, this);
订阅有效,但在回发中,NPE被抛入UIComponent
(Mojarra 2.2.9),因为wrapped
在以下方法中为空
public boolean isListenerForSource(Object component) {
if (wrapped instanceof SystemEventListener) {
return ((SystemEventListener) wrapped).isListenerForSource(component);
} else {
return instanceClass.isAssignableFrom(component.getClass());
}
}
这可能是因为实际组件似乎是在提交数据时新创建的,因此订阅&#39;迷路了。
在ViewRoot
上注册不起作用,因为事件来源始终是ViewRoot
,并且在Application
上注册是完全错误的。
我可能正在寻找错误方向的解决方案,但现在我一无所知。请记住,我无法直接控制创建的ui控件,如果可以阻止,我也不想覆盖它们的渲染器。因此,从子控件发出父节点信号不是一个选项。
我试过的其他事情:
这一切都是Mojarra高达2.2.9(尚未检查更新或MyFaces)
答案 0 :(得分:1)
在PreRenderViewEvent中添加组件可以很好地工作。问题是,您似乎无法在请求期间订阅事件。重新创建实际的组件(在RestoreViewPhase我假设,没有检查),然后订阅事件仍然存在,只是包裹&#39;应该调用它的上下文是空的。
在此特定组件的PostRestoreStateEvent中添加PostValidationEvent事件(它是FacesContext.getCurrentInstance().getPartialViewContext().getExecuteIds()
中唯一的一个),使其在注释中提到。在下一个请求中摆脱NPE的技巧(黑客/解决方法/ ...)实际上是删除事件。
((UIComponent) event.getSource()).unsubscribeFromEvent(PostValidateEvent.class, this);
我尝试创建一个没有任何PrimeFaces或OmniFaces的示例,看看会发生什么,因为它们似乎都是上下文的包装器,我想确保它们不是行为的原因。