我正在尝试在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);
}
}
答案 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设置所需的类名。