订阅动态创建的子组件的事后验证事件

时间:2015-03-19 22:50:39

标签: jsf-2 jsf-2.2

对于我喜欢使用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控件,如果可以阻止,我也不想覆盖它们的渲染器。因此,从子控件发出父节点信号不是一个选项。

我试过的其他事情:

  • 使用valueChangeListeners,但是在许多其他问题(包括使其可扩展的方法)中都不起作用。
  • 使用带绑定的复合组件但是动态包含它们失败,要求命名容器与框架其余部分所需的id冲突,xhtml中的标签,提示和警报的位置和/或结果DOM
  • 用于在创建树时操纵树的Taghandler

这一切都是Mojarra高达2.2.9(尚未检查更新或MyFaces)

1 个答案:

答案 0 :(得分:1)

在PreRenderViewEvent中添加组件可以很好地工作。问题是,您似乎无法在请求期间订阅事件。重新创建实际的组件(在RestoreViewPhase我假设,没有检查),然后订阅事件仍然存在,只是包裹&#39;应该调用它的上下文是空的。

在此特定组件的PostRestoreStateEvent中添加PostValidationEvent事件(它是FacesContext.getCurrentInstance().getPartialViewContext().getExecuteIds()中唯一的一个),使其在注释中提到。在下一个请求中摆脱NPE的技巧(黑客/解决方法/ ...)实际上是删除事件。

((UIComponent) event.getSource()).unsubscribeFromEvent(PostValidateEvent.class, this);

我尝试创建一个没有任何PrimeFaces或OmniFaces的示例,看看会发生什么,因为它们似乎都是上下文的包装器,我想确保它们不是行为的原因。