0

I am trying to write a simple create user page. I want the user to be able to type a desired username and if the username is already taken, then an output text shows up and says "Username already in use".

Here is my xhtml page

<tr>
                        <td>Username: </td>
                        <td>
                        <p:inputText id="username" value="#{createUserManagedBean.username}" required="true" requiredMessage="Username is required.">
                            <p:ajax event="keyup" update="uniqueUsernameMessage"/>
                        </p:inputText>                          
                        </td>
                        <td>
                            <h:outputText id="uniqueUsernameMessage" value="Username already in use" rendered="#{!createUserManagedBean.checkUniqueUsername()}" />
                        </td>
                    </tr>

Here is my managed bean

public boolean checkUniqueUsername()
{
    if(!StringUtils.isBlank(getUsername()))
    {
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername(username);
        boolean result = getUserService().validateUniqueUsername(userDTO);
        return result;
    }
    else
        return false;
}

My issue is that the message is not updating for each keyup event. The service was being called, but the element was not changing whether or not it would display or not depending on the method result.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Scott
  • 174
  • 5
  • 19
  • ... and what is the question? Does an error occur? If so, add it to your question! We can't figure out what's wrong if you don't provide more information. – Manuel Sep 05 '13 at 08:51
  • Manuel, I apologize for not stating my exact issue. My question is now updated with my issue. – Scott Sep 05 '13 at 23:16
  • When you have an update to the question, please don't change the initial question drastically in such way that the answers are not making any sense anymore. Instead, *add* the update in a new section in the question. I've rolledback the edit (and posted a comment on my answer about your mistake). – BalusC Sep 06 '13 at 00:06

1 Answers1

2

Using the rendered attribute is absolutely not the right way to validate an input component. You should be using a real Validator implementation. Therein you can in case of invalidation just throw a ValidatorException with a FacesMessage. JSF will then take care that the FacesMessage ends up in the right <h:message> associated with the input component.

All in all, this should do:

<p:inputText id="username" value="#{createUserManagedBean.username}" ...>
    <f:validator binding="#{uniqueUsernameValidator}" />
    <p:ajax event="keyup" update="usernameMessage" />
</p:inputText>
<h:message id="usernameMessage" for="username" />

With

@ManagedBean
@RequestScoped
public class UniqueUsernameValidator implements Validator {

    @EJB
    private UserService userService;

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        if (value == null || value.isEmpty()) {
            return; // Let required="true" handle.
        }

        String username = (String) value;

        if (userService.findByUsername(username) != null) {
            throw new ValidatorException(new FacesMessage(
                FacesMessage.SEVERITY_ERROR, "Username already in use. Please choose another", null));
        }
    }

}

See also:


Please note that the validator is a @ManagedBean instead of a @FacesValidator because the @EJB could otherwise not be injected. But if you're not using EJBs and are manually creating service classes and fiddling with transactions yourself, then you could probably just keep it a real @FacesValidator:

@FacesValidator("uniqueUsernameValidator")
public class UniqueUsernameValidator implements Validator {

Which is then instead to be referenced as follows:

<f:validator validatorId="uniqueUsernameValidator" />

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thank you BalusC for a nice example and reference of how a jsf validator should be written. Unfortunately, this does not fix my issue (I somehow forgot to state my exact issue, I will update the question). – Scott Sep 05 '13 at 23:13
  • My answer not only solves your problem, but also guides you in the right direction. If you *really* want to stick to abusing the `rendered` attribute and a getter method to perform validation and show validation messages instead of a normal `Validator` with a ``, then read this: http://stackoverflow.com/questions/8487422/render-component-with-ajax-in-jsf/8488251#8488251 – BalusC Sep 05 '13 at 23:38
  • I changed to using the validator (the way you described above), but it is not updating for each keyup event. – Scott Sep 05 '13 at 23:45
  • Then the problem is not visible in the information provided so far. The code in my answer is correct. Perhaps you changed it a bit too much without actually understanding what you're doing? – BalusC Sep 05 '13 at 23:47
  • I will update my question with all current code. Please note that I did not inject my userService tier to actually hit the database. I am just doing a string evaluation so I can test it quickly. – Scott Sep 05 '13 at 23:53
  • As per your question update, why are you using `` instead of ``? – BalusC Sep 06 '13 at 00:05
  • No reason at all, I guess that is what I saw online. I changed it to message now. Thank you so much for dealing with my beginner questions and problems. You initially did fix it, please forgive my ignorance of not paying complete attention to your examples. – Scott Sep 06 '13 at 00:06
  • The `` can't show a `FacesMessage`. The `` should be used therefor. It's exactly as shown in my answer (and in many many JSF tutorials). I've even explained it in the 1st paragraph of the answer. Have you also read it instead of only staring at the code blocks? – BalusC Sep 06 '13 at 00:07