样式化验证失败的UIInputs

时间:2013-08-08 00:21:24

标签: validation jsf styling

问题

我正在尝试在jsf 1.2中使用表单验证。我有一个包含两个输入文本字段行的表单。

我输入两行数据,其中包含一个坏单元格,如下所示:

| :) | :/ |
| :) | :) |

每行调用一次验证器,但检查两个字段。 验证失败的每个UIInput都会添加到失败的UIComponent列表中。 提交操作的方法最终会运行。 首先,它恢复任何已保存的样式。 然后它遍历失败的UIComponent。 在循环内部,它保存当前样式,然后将样式设置为“badInput”。

但是当页面加载时,两个end-cell都具有“badInput”样式:

| :) | :/ |
| :) | :/ |

我的代码

这是我的验证器,托管bean上处理此页面的方法:

public void validateTime(FacesContext context, UIComponent component, Object value)
{
  UIInput out = (UIInput) component.findComponent("out");

  for (UIComponent uic : Arrays.asList(component, out))
  {
    String time = (String) ((UIInput)uic).getSubmittedValue();

    if (!StringToTime.isValid(time))
    {
      // mark that we found invalid times
      validTimes = false;

      // save the failed component
      // the click method will change the style during the render phase
      failedUics.add(uic);  // List<UIComponent>
      badComps.put(uic.getClientId(context), uic);  // Map<String, UIComponent>
    }
  }
}

这是输入字段表:

<h:dataTable binding="#{entryHandler.tableAttends}" value="#{entryHandler.attends}" var="range">
  <h:column>
    <div>
      <h:outputLabel>
        <h:outputText value="In: " />
        <h:inputText value="#{range.start}" id="in" validator="#{entryHandler.validateTime}" />
      </h:outputLabel>

      <h:outputLabel>
        <h:outputText value="Out: " />
        <h:inputText value="#{range.end}" id="out" />
      </h:outputLabel>

      <h:commandLink action="#{entryHandler.delAttend}" value="X" styleClass="removeTime" />
    </div>
  </h:column>
</h:dataTable>

我尝试过这两种方式应用错误的输入方式:

for (UIComponent target : failedUics)
{
  log.debug("target client id: " + target.getClientId(context));

  Map<String, Object> attr = target.getAttributes();

  // save the style before changing it
  String style = (String) attr.get("styleClass");
  originalStyle.put(target.getClientId(context), style);

  // add the badInput css class
  if (style == null) style = "";
  attr.put("styleClass", "badInput " + style);
}
failedUics = new ArrayList<UIComponent>();

和第二个:

UIComponent root = context.getViewRoot();
for (String clientId : badComps.keySet())
{
  root.invokeOnComponent(context, clientId, new BadInputCallback(originalStyle));
}
badComps = new HashMap<String, UIComponent>();

这是回调函数:

private static class BadInputCallback implements ContextCallback
{
  private final Map<String, String> originalStyle;

  public BadInputCallback(Map<String, String> originalStyle)
  {
    this.originalStyle = originalStyle;
  }

  @Override
  public void invokeContextCallback(FacesContext context, UIComponent target)
  {
    Map<String, Object> attr = uic.getAttributes();

    // save the style before changing it
    String style = (String) attr.get("styleClass");
    originalStyle.put(target.getClientId(context), style);

    // add the badInput css class
    if (style == null) style = "";
    attr.put("styleClass", "badInput " + style);
  }
}

1 个答案:

答案 0 :(得分:1)

导致您的具体问题是因为组件树中只有物理只有一个输入组件,只要父UIData组件迭代模型的每个项目,其状态就会发生变化。如果要动态设置styleClass,基本上需要让它依赖于当前迭代的项目,如下所示:

<h:dataTable ... var="item">
    <h:column>
        <h:inputText ... styleClass="#{item.bad ? 'badInput' : ''}" />
    </h:column>
</h:dataTable>

或者当你已经使用JSF 2.x时,请检查UIInput#isValid(),然后通过隐式EL变量UIInput引用#{component},如下所示:

<h:dataTable ... var="item">
    <h:column>
        <h:inputText ... styleClass="#{component.valid ? '' : 'badInput'}" />
    </h:column>
</h:dataTable>

此问题之前已经确定并且已经考虑到了JSF 1.2目标SetFocusListener phase listener on The BalusC Code和JSF实用程序库<o:highlight> component的JSF 2.0 OmniFaces

两者都采用相同的方法:它们收集所有无效输入组件的客户端ID,并将它们作为数组传递给JavaScript代码,然后通过HTML DOM设置所需的类名。

另见: