jsf - Styling UIInputs that fail validation -
the problem
i'm trying work form validation in jsf 1.2. have form rows of 2 input text fields.
i enter 2 rows of data, 1 bad cell, this:
| :) | :/ | | :) | :) |
the validator called once each row, checks both fields. each uiinput
fails validation added list of failed uicomponent
s. method submit action gets run. first restores saved styles. loops on failed uicomponent
s. inside loop, saves current style, sets style "badinput".
but when page loads, both end-cells have "badinput" style:
| :) | :/ | | :) | :/ |
my code
this validator, method on managed bean handles page:
public void validatetime(facescontext context, uicomponent component, object value) { uiinput out = (uiinput) component.findcomponent("out"); (uicomponent uic : arrays.aslist(component, out)) { string time = (string) ((uiinput)uic).getsubmittedvalue(); if (!stringtotime.isvalid(time)) { // mark found invalid times validtimes = false; // save failed component // click method change style during render phase faileduics.add(uic); // list<uicomponent> badcomps.put(uic.getclientid(context), uic); // map<string, uicomponent> } } }
and here's 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 bad input style these 2 ways:
for (uicomponent target : faileduics) { log.debug("target client id: " + target.getclientid(context)); map<string, object> attr = target.getattributes(); // save style before changing string style = (string) attr.get("styleclass"); originalstyle.put(target.getclientid(context), style); // add badinput css class if (style == null) style = ""; attr.put("styleclass", "badinput " + style); } faileduics = new arraylist<uicomponent>();
and second:
uicomponent root = context.getviewroot(); (string clientid : badcomps.keyset()) { root.invokeoncomponent(context, clientid, new badinputcallback(originalstyle)); } badcomps = new hashmap<string, uicomponent>();
where 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 style before changing string style = (string) attr.get("styleclass"); originalstyle.put(target.getclientid(context), style); // add badinput css class if (style == null) style = ""; attr.put("styleclass", "badinput " + style); } }
your concrete problem caused because there physically only one input component in component tree, state changes whenever parent uidata
component iterates on every item of model. when want set styleclass
dynamically, need let depend on iterated item, so:
<h:datatable ... var="item"> <h:column> <h:inputtext ... styleclass="#{item.bad ? 'badinput' : ''}" /> </h:column> </h:datatable>
or when you're on jsf 2.x, check uiinput#isvalid()
instead whereby uiinput
referenced via implicit el variable #{component}
, so:
<h:datatable ... var="item"> <h:column> <h:inputtext ... styleclass="#{component.valid ? '' : 'badinput'}" /> </h:column> </h:datatable>
this problem identified before , taken account in among others jsf 1.2 targeted setfocuslistener
phase listener on balusc code , jsf 2.0 <o:highlight>
component of jsf utility library omnifaces.
both have under covers same approach: collect client ids of invalidated input components , pass them array javascript code in turn sets desired class name via html dom.
Comments
Post a Comment