the problem
I'm trying to work with form validation in jsf 1.2. I have a form with rows of two input text fields.
I enter two rows of data, with one bad cell, like this:
| :) | :/ |
| :) | :) |
The validator is called once for each row, but checks both fields.
Each UIInput
that fails validation is added to a list of failed UIComponent
s.
The method for the submit action finally gets to run.
First it restores any saved styles.
Then it loops over the failed UIComponent
s.
Inside the loop, it saves the current style, then sets the style to "badInput".
But when the page loads, both end-cells have the "badInput" style:
| :) | :/ |
| :) | :/ |
my code
This is my validator, a method on the managed bean that handles this page:
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>
}
}
}
And here's the table of input fields:
<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>
I've tried applying the bad input style these two ways:
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>();
and the second:
UIComponent root = context.getViewRoot();
for (String clientId : badComps.keySet())
{
root.invokeOnComponent(context, clientId, new BadInputCallback(originalStyle));
}
badComps = new HashMap<String, UIComponent>();
where this is the callback function:
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);
}
}