Search code examples
validationjsfrequiredrendered-attribute

Why is required="true" not triggered when rendered="false"


I have a some doubts about parsing of html tags in facelet. Let we have facelet which contains the follow

<h:inputText id="username"
             title="My name is: "
             value="#{hello.name}"
             required="true"
             requiredMessage="Error: A name is required."
             rendered="false"
             maxlength="25" />
<h:commandButton id="submit" value="Submit" action="response">
            </h:commandButton>

After submit click i haven't Error: A name is required. Why? username just not rendered, and after submit click there is no value in username.


Solution

  • The rendered attribute is also evaluated during validations and update model values phases. For evidence, check javax.faces.component.UIInput source code (line numbers are as per Mojarra 2.2.0):

    696     public void processValidators(FacesContext context) {
    697 
    698         if (context == null) {
    699             throw new NullPointerException();
    700         }
    701 
    702         // Skip processing if our rendered flag is false
    703         if (!isRendered()) {
    704             return;
    705         }
    ...
    ...
    ...
    735     public void processUpdates(FacesContext context) {
    736 
    737         if (context == null) {
    738             throw new NullPointerException();
    739         }
    740 
    741         // Skip processing if our rendered flag is false
    742         if (!isRendered()) {
    743             return;
    744         }
    

    The explanation is simple: this is a safeguard against tampered (spoofed/hacked) HTTP requests wherein endusers purposefully manipulate the HTTP request in an attempt to set values and/or invoke actions of hidden inputs/commands which they are most likely simply not allowed to update or invoke, such as a delete button which shows only when the user has admin role:

    <h:commandButton value="Delete" ... rendered="#{request.isUserInRole('ADMIN')}" />
    

    Note: component's readonly and disabled attributes are also treated this way. For your particular purpose, use CSS display: none instead.

    <h:inputText ... style="display:none" />
    

    (note: this is a kickoff example, using style attribute is bad practice in HTML/CSS perspective, prefer styleClass with a concrete CSS file)

    Although I wonder the concrete functional requirement behind this, this is bad for UX. Perhaps you were just randomly experimenting around without first studying the JSF specification let alone JSF source code?