Search code examples
javajsf-2glassfishfacelets

h:message elements with for attribute do not present messages in JSF 2


I have the following authentication form in JSF running on Glassfish 3:

<h:messages globalOnly="true" errorClass="erro" />
<h:form id="form-login">
    <h:outputText value="User" />
    <h:message for="login-user" />
    <h:inputText id="login-user" 
        value="#{authenticationBean.user}" showMessages="true" />

    <h:outputText value="Password" />
    <h:inputSecret id="login-password" 
        value="#{authenticationBean.password}" />

    <h:commandButton id="Log in" 
        action="#{authenticationBean.logIn}" value="Autenticar-se" />
</h:form>

The authentication.logIn method is the one below:

public String logIn() {
    user = userDAO.authenticate(user, password);
    if (user != null) {
        FacesMessage message = new FacesMessage("Welcome!");
        message.setSeverity(FacesMessage.SEVERITY_INFO);
        FacesContext.getCurrentInstance().addMessage(null, message);
        return "ok";
    } else {
        FacesMessage message = new FacesMessage("Authentication failed");
        message.setSeverity(FacesMessage.SEVERITY_ERROR);
        FacesContext.getCurrentInstance().addMessage(null, message);
        if ("".equals(user)) {
            message = new FacesMessage("You need to give a user");
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            FacesContext.getCurrentInstance().addMessage(
                "login-user", message);
        }
        return "fail";
    }
}

I try to show an specific message if the user login is not given, with the line <h:message for="login-user" />. It does not work, though: if I click in the submit button with an empty user field, the <h:messages globalOnly="true" errorClass="erro" /> element presents the "Authentication failed" but the <h:message for="login-user" /> component just does not present the "You need to give a user" text as I expected. Instead it presents no message at all. Also, the following warning appears on the log:

[lifecycle] WARNING: FacesMessage(s) have been enqueued, but may not have been displayed.
sourceId=login-user[severity=(ERROR 2), summary=(You need to give a user), detail=(You need to give a user)]

(Actually, I looked for some translation in Google, since the real message I got is in Portuguese:

INFO: WARN: FacesMessage(s) foram enfileirados, mas podem não ter sido exibidos.
sourceId=login-usuario[severity=(ERROR 2), summary=(You need to give a user), detail=(You need to give a user)]

)

What am I doing wrong?

Thanks in advance!


Solution

  • You need to specify the client ID, not the component ID. Based on the given view code, that'll be:

    FacesContext.getCurrentInstance().addMessage(
        "form-login:login-user", message);
    

    If that doesn't work, you need to open the page in browser and view its generated HTML source. It should be the same as id attribute of generated HTML <input> element.


    Unrelated to the problem, I usually use null as client ID and use a <h:messages globalOnly="true"> for general validation errors. You may want to take the same approach. For the "You need to give an user" part I'd just use required="true" instead.