CSS Style Change with Jsf Validation

Css Style change with JSF Validation

You could do this with a managed bean:

public class ValidBean {

private UIComponent myComponent;

public UIComponent getMyComponent() {
return myComponent;
}

public void setMyComponent(UIComponent myComponent) {
this.myComponent = myComponent;
}

public String getErrorStyle() {
FacesContext context = FacesContext
.getCurrentInstance();
String clientId = myComponent.getClientId(context);
Iterator<FacesMessage> messages = context
.getMessages(clientId);
while (messages.hasNext()) {
if (messages.next().getSeverity().compareTo(
FacesMessage.SEVERITY_ERROR) >= 0) {
return "background-color: red";
}
}
return null;
}
}

Request scope variable:

  <managed-bean>
<managed-bean-name>validBean</managed-bean-name>
<managed-bean-class>stylevalid.ValidBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

Sample view:

  <f:view>
<h:form>
<h:inputText binding="#{validBean.myComponent}" styleClass="foo"
style="#{validBean.errorStyle}">
<f:validateLength minimum="6" />
</h:inputText>
<h:commandButton />
<h:messages />
</h:form>
</f:view>

The component is bound to the backing bean. If error messages have been queued for the component, it overrides its CSS class settings with its style attribute.

How to change css class for the inputfield and label when validation fails?

Bind the input component to the view via binding attribute. It'll become available as an UIInput component reference in EL, so that you can use UIInput#isValid() in styleClass attribute.

<h:outputLabel for="emailInput" value="Email" 
styleClass="#{emailInput.valid ? '' : 'error'}" />

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

(note that I fixed your label to be a real label; also note that you don't need to create some bean property at all as suggested by the answer of cubbuk)

Yes, this may produce quite some non-DRY boilerplate code in the view. You can abstract this away with a phase listener or a system event listener. You can also use OmniFaces <o:highlight> component which does all the job transparently. See also the live demo.

Styling UIInputs that fail validation

Your concrete problem is caused because there is physically only one input component in the component tree, whose state changes whenever the parent UIData component iterates over every item of the model. When you want to set the styleClass dynamically, you basically need to let it depend on the currently iterated item, like so:

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

Or when you're already on JSF 2.x, then check UIInput#isValid() instead whereby the UIInput is referenced via implicit EL variable #{component}, like so:

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

This problem is already identified before and taken into account in among others the JSF 1.2 targeted SetFocusListener phase listener on The BalusC Code and the JSF 2.0 <o:highlight> component of JSF utility library OmniFaces.

Both have under the covers the same approach: they collect the client IDs of all invalidated input components and pass them as an array to JavaScript code which in turn sets the desired class name via HTML DOM.

See also:

  • What exactly is #{component} in EL?
  • how to set ui-state-error class to h:selectOneMenu on validation error
  • Styling input component after validation failed
  • Eclipse errors on #{component.valid}: "valid cannot be resolved as a member of component”

Styling input component after validation failed

Your concrete problem is caused because you didn't update the input component on complete of the ajax request. You're only updating the growl component. So the changes to the input component are never reflected into the client side.

I suggest to just update the entire form as it might contain other input components which also needs to be highlighted:

<p:commandButton ... update="@form" />

By the way, the @ListenersFor (and @ListenerFor) is misplaced here. It doesn't work that way and they're plain ignored. Get rid of them. See also How to register a (Component)SystemEventListener for all UIInputs.


Unrelated to the concrete problem, this SystemEventListener approach to highlight failed input components is flawed. It will fail when the input component is inside an iterating component such as <ui:repeat> or <h:dataTable>. It would highlight the input component in all rows even when only one of them has failed.

Better go for a client side approach instead. The JSF utility library OmniFaces offers the <o:highlight> component for exactly this purpose. See also the <o:highlight> tag documentation, the <o:highlight> showcase example and the <o:highlight> source code.

Possible to set the styleClass of a xp:control from validator class?

The explicit call to setStyleClass method of UIComponent casted to XspInputText works for me

((XspInputText)component).setStyleClass("my-class");

If you don't want to cast but want to apply the styleClass to any component that supports such property, java reflection can help:

try {
Method setStyleClass = component.getClass().getMethod("setStyleClass", String.class);
if (setStyleClass != null) {
setStyleClass.invoke(component, "my-class");
}
} catch (SecurityException e) {}
catch (NoSuchMethodException e) {}
catch (IllegalArgumentException e) {}
catch (IllegalAccessException e) {}
catch (InvocationTargetException e) {}

You may want to append the styleClass instead of replace

try {
String styleClass = null;
Method getStyleClass = component.getClass().getMethod("getStyleClass");
if (getStyleClass != null) {
styleClass = (String)getStyleClass.invoke(component, (Object[])null);
}
Method setStyleClass = component.getClass().getMethod("setStyleClass", String.class);
if (setStyleClass != null) {
String newStyleClass = StringUtil.isNotEmpty(styleClass) ? styleClass.concat(" my-class") : "my-class";
setStyleClass.invoke(component, newStyleClass);
}
} catch (SecurityException e) {}
catch (NoSuchMethodException e) {}
catch (IllegalArgumentException e) {}
catch (IllegalAccessException e) {}
catch (InvocationTargetException e) {}

Why JSF form maintain the validation styles even if has values on it?

What happens when you click the Escanear button is that you are processing the whole form, thus submitting all the fields with empty values, this will cause validation errors, your button is immediate so what happens is the following:

  1. actionListener is immediate so it's called first and the managed bean is filled with data from a barcode scanner.
  2. the form data is being validated and it's not valid so the inValid flag is set on all the inputs.
  3. the response is created on the server containing an update for the form, showing the new values from the managed bean and the inValid state of the inputs from the validation process.

notice that the submitted data (empty values) is not applied to the model as it's not valid.

to fix this, just use partial processing feature on your button, and remove the immediate="true", it's just a bad design.

just replace immediate="true" with process="@this" in the Escanear button.

If you're not familiar with partial processing feature of JSF and primefaces you should give it a look.

if you really need to submit the form for validation after the scan is complete then you need to use a p:remoteCommand that submits the form after the actionListener is complete:

    <p:remoteCommand name="validateForm" process="@form"/>

<p:commandButton value="#{label['manageVipLoungeEntrance.addPassenger.button.scan']}"
onclick="showLocalDate()" update=":frmScan" process="@this"
actionListener="#{manageVipLoungeEntranceExtMB.clear}"
oncomplete="{wgvScan.show()}" />

and in the other form frmScan do:

<h:form id="frmScan">
<p:dialog widgetVar="wgvScan" modal="true" showEffect="fade"
closeOnEscape="true" resizable="false" onHide="validateForm()">
....
....complete your code

the name of the p:remoteCommand becomes a javascript function that can be called back once the scan dialog is hidden.

Note bring up the dev console in your browser and watch the two requests one for updating the form and closing the dialog and the other one caused by p:remoteCommand to validate the form.

Note 1 (not related to your question) that I used the frmScan to enclose p:dialog this is the right way to do it, the form should surround the dialog not the other way around.

Dynamically change CSS style of cell in h:dataTable column

You can just use the conditional operator ?: in EL.

E.g.

<c:set var="B" value="#{(list.A / list.C) * 100}" />
<h:outputText value="#{B}" style="display: block; background-color: #{B lt 50 ? 'red' : (B lt 90 ? 'blue' : 'green')}" />

If B is also used elsewhere in the model or controller, then you could add a public int getB() method which just contains return (A/C) * 100; and then use #{list.B} instead of #{B}.

Note that proper design is to use a CSS class instead. E.g.

<h:outputText value="#{B}" styleClass="percentage #{B lt 50 ? 'poor' : (B lt 90 ? 'average' : 'good')}" />

with

td .percentage {
display: block;
}

.percentage.poor {
background-color: red;
}

.percentage.average {
background-color: blue;
}

.percentage.good {
background-color: green;
}

You can of course also perform the determination of CSS style/class in a getter method as suggested by the other answer, but that's a poor separation of concerns.

Change default color of * in PrimeFaces validation

You need to change the CSS from your theme.

Example:

.ui-outputlabel .ui-outputlabel-rfi {
color: blue;
}


Related Topics



Leave a reply



Submit