2

How can I style a component after validation failed?

I have the following textfield:

<p:inputText id="username" value="#{authController.username}" autocomplete="off" required="true" />

I am trying to change the color after the:

<p:commandButton id="submit" value="Login" actionListener="#{authController.login}" update=":growl" />

Is clicked.

I have found this site and tried to implement the way has been shown there.

This is my class:

public class RequiredFieldValidationListener implements SystemEventListener {

    public boolean isListenerForSource(Object source) {
        return true;
    }

    public void processEvent(SystemEvent event) throws AbortProcessingException {
        if (event.getSource() instanceof UIInput) {
            UIInput source = (UIInput) event.getSource();

            if (!source.isValid()) {
                String originalStyleClass = (String) source.getAttributes().get("styleClass");
                source.getAttributes().put("data-originaStyleClass", originalStyleClass);
                source.getAttributes().put("styleClass", originalStyleClass + " ui-input-invalid");
            } else {
                String originalStyleClass = (String) source.getAttributes().get("data-originaStyleClass");
                source.getAttributes().put("styleClass", originalStyleClass);
            }
        }
    }
}

I am registering it in faces-config.xml as:

<application>
    ---

    <system-event-listener>
        <system-event-listener-class>com.edfx.adb.web.event.RequiredFieldValidationListener</system-event-listener-class>
        <system-event-class>javax.faces.event.PostValidateEvent</system-event-class>
        <source-class>javax.faces.component.html.HtmlInputText</source-class>                       
    </system-event-listener>

</application>

Also I have tried to use

@ListenersFor({ @ListenerFor(sourceClass = HtmlInputText.class, systemEventClass = PostValidateEvent.class) })
public class RequiredFieldValidationListener implements SystemEventListener {

}

I was expecting that when the input field is invalid, for my case, blank, the css class ui-input-invalid will be added to the class attribute of the component. But it is not working. I fact the method processEvent is not executing at all.

What I am doing wrong and how can I achieve this?

Tapas Bose
  • 28,796
  • 74
  • 215
  • 331

2 Answers2

4

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.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Heh almost always omnifaces seem to have what is needed. Very nice :) – Aksel Willgert Dec 09 '12 at 13:55
  • @Aksel: that's exactly the philosophy behind OmniFaces :) – BalusC Dec 09 '12 at 13:57
  • Thanks BalusC, very nice solution and it works. Primarily it wasn't working, as I had set `javax.faces.PARTIAL_STATE_SAVINGfalse` in my web.xml, after removing this context-param it works. I would like to know what is the relationship between this context-param with `o:highlight`? Is there any way to use both of it? – Tapas Bose Dec 09 '12 at 16:28
  • Also there is another point I would like to tell you, that I left two inputs blank and click the button, then those two input fields get colored. After that I fill up any one of it and click again the button, I was expecting to get only that input highlighted which is blank, but in practical scenario I saw that the previously highlighted input still highlighted, after firebugging I found that the css class error is still there. Is it the actual behavior? How can I solve this issue? – Tapas Bose Dec 09 '12 at 16:29
  • It has the same answer as your initial question: update the form on submit. As to partial state saving, thank you, I wasn't aware of this behavior and I will take a look at it. – BalusC Dec 09 '12 at 16:34
  • Sorry, can't reproduce "doesn't work "problem with partial state saving turned off (OmniFaces 1.3 snapshot and Mojarra 2.1.14). Feel free to report to issue tracker of OmniFaces along with a concrete WAR demonstrating the problem. – BalusC Dec 09 '12 at 16:39
  • Hello @BalusC, I have created a ticket: http://code.google.com/p/omnifaces/issues/detail?id=110 – Tapas Bose Dec 10 '12 at 08:00
1

I tried the linked example and got the SystemEventListener.processEvent() to trigger when using

<h:inputText ... required="true"/>

So i figured it has do with faces-config.xml. Specifying the primefaces InputText as source-class did the trick:

<application>
    <system-event-listener>
        <system-event-listener-class>RequiredFieldValidationListener</system-event-listener-class>
        <system-event-class>javax.faces.event.PostValidateEvent</system-event-class>
        <source-class>org.primefaces.component.inputtext.InputText</source-class>
    </system-event-listener>
</application>

to use

<p:inputText ... required="true"/>
Aksel Willgert
  • 11,367
  • 5
  • 53
  • 74
  • Thanks. Now the method is executing, but `source.getAttributes().get("styleClass");` is returning `null`, also I tried to iterate the `Map` `source.getAttributes()` to see it's elements, but there is no such key, I found only two key-value pairs: `javax.faces.component.VIEW_LOCATION_KEY : /login.xhtml @21,44 com.sun.faces.facelets.MARK_ID : 2030916047_790d5125`. Also the other functionality, like I have a `Growl` which was showing required field validation error messages, doesn't show anymore. I tried to cast it with `InputText` instead of `UIInput`, but no luck. – Tapas Bose Dec 09 '12 at 09:02