JSF2 + IceFaces 2 - 从ViewRoot中检索UIComponent

时间:2011-12-09 08:52:03

标签: jsf-2 uicomponents icefaces-2 viewroot

我很难解决以下问题。我的问题很简单:我想用红色突出显示触发验证错误的表单字段。使用context.addMessage(...)行将错误消息正确放置在FacesContext中。

我希望我的系统是通用的。所有附有消息的表单字段都会自动突出显示。

我在本网站上找到了这篇优秀文章的链接: http://www.jroller.com/mert/entry/how_to_find_a_uicomponent

有了它,我确实为RENDER_RESPONSE阶段实现了一个PhaseListener,它执行以下操作:

@Override
  public void beforePhase(PhaseEvent event) {
    // get context
    FacesContext context = event.getFacesContext();

    // iterate on all the clientIds which have messages
    Iterator<String> clientIdsWithMessages = context.getClientIdsWithMessages();
    while (clientIdsWithMessages.hasNext()) {

      // get the clientId for the field component
      String clientIdWithMessage = clientIdsWithMessages.next();
      // split on ":"
      String[] splitted = clientIdWithMessage.split(":");

      UIComponent component = findComponentInRoot(splitted[splitted.length - 1]);
      if (component != null) {
        Map<String, Object> attributes = component.getAttributes();

        if (attributes.containsKey("style")) {
          attributes.remove("style");
        }
        attributes.put("style", "background-color: #FFE1E1;");
      }
    }
  }

这几乎适用于我的所有用途。

现在,它变得有点棘手,是我的一些表单有这样的代码:

<ice:dataTable id="revisionDocuments" value="#{agendaBean.agenda.revisionsDocuments}" var="revision">
    <ice:column>
        <ice:inputText value="#{revision.sequenceAdresse}" id="revisionSequenceAdresse" />
    </ice:column>
    ....

生成的表单有几行(revisionsDocuments列表的每个对象一行),每个元素都有一个唯一的标识符(clientId),如下所示:

contentForm:revisionDocuments:0:revisionSequenceAdresse

每次迭代为0改为1,2,.... 因此,从ViewRoot搜索UIComponent所提供的代码无法正常工作。所有表单字段都具有相同的&#34; id&#34;。让我更加惊讶的是:他们拥有相同的&#34; clientId&#34;在FacesContext中也是:

contentForm:revisionDocuments:revisionSequenceAdresse

在穿过树时,我无法区分,如果我确实看到了正确的表格字段或任何其他字段。

有人有提示要解决这个问题吗?或者另一个建议来实现我的领域的亮点?我不得不承认,我真的不喜欢我的代码,我认为操作viewRoot很脏,就像我做的那样,但是我无法想出一个更好的解决方案来获得我的字段的一般亮点。

我在JBOss AS 7.0.2.Final上使用JSF-Impl 2.1.1-b04运行IceFaces 2.0.2。

提前感谢您的答案。 最好的祝福, 帕特里克

2 个答案:

答案 0 :(得分:2)

您应该在客户端应用此功能。您有一组带有消息的客户端ID。其中一种方法是将此信息传递给JavaScript并让它完成工作。您可以在本文中找到此类PhaseListener的示例:Set focus and highlight in JSF

从JSF 2.0开始,不需要PhaseListener就可以采用另一种方式。有一个新的隐式EL变量#{component},它引用当前组件的UIComponent实例。如果是UIInput个组件,则会有isValid()个方法。这允许您执行以下操作:

<h:inputText styleClass="#{component.valid ? '' : 'error'}" />

在CSS文件中使用:

.error {
    background: #ffe1e1;
}

(是的,您也可以在style属性中执行此操作,但使用标记混合样式是一种不好的做法)

要抽象出来(这样你就不需要在每个输入中重复它),你可以为此创建一个composite component,类似于<my:input>

答案 1 :(得分:0)

为了完整性,这里是我最终发现的解决方案,突出显示有IceFaces 2.0.2错误消息的字段:

基本思想与BalusC在http://balusc.blogspot.com/2007/12/set-focus-in-jsf.html

提出的建议完全相同

我必须使用IceFaces更改的代码是一个小的Javascript调用:

<script>
    setHighlight('${highlight}');
</script>

我找不到任何在每次JS调用时重新渲染的IceFaces组件。我发现将脚本放入panelGroup大部分时间都可以工作。但是,有一个案例不起作用:

提交有错误的表单会触发JS。 然后,重新提交与先前验证相同的字段上的错误表单不会触发JS。 然后,重新提交任何错误字段没有更多错误的表单会触发JS。 然后,重新提交带有错误的任何非错误字段的表单会触发JS。

出于某种原因,当两个调用之间有错误的字段集相同时,IceFaces不会呈现包含JS的panelGroup。

我尝试将Javascript API与Ice.onAsynchronousReceive()等代码一起使用,使用Prototype库将事件附加到commandButton的AJAX完成,但是没有取得多大成功。我的一些测试可以运行(有错误但是完成了工作),我可以观察到类似的行为。

这是我最终使用的技巧(丑陋但有效):

<ice:panelGroup>
    <script type="text/javascript">
        var useless = '#{testBean.time}';
        setHighlight('${highlight}');
    </script>
</ice:panelGroup>

getTime()函数只返回当前时间戳。然后,该值始终不同,并在任何AJAX请求时触发JS执行。

可悲的是,IceFaces没有RichFaces有用的“oncomplete”属性,我对此案感到非常遗憾。

丑陋的解决方案,但有趣且有效。