0
votes

In this page I,m going to let the user to make the password visible by clicking a checkbox. Actually two Inputs (password, conPassword) should hide and another input (passwordV) should be displayed. All these 3 inputs have the same value and needs to keep their values as user switches between these 2 states: (having two secret fields visible or having one plain text field)

I put the page and bean code here:

JSF Page:

<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
                template="./templates/main_template.xhtml"
                xmlns:p="http://primefaces.org/ui"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:f="http://java.sun.com/jsf/core"
                xmlns="http://www.w3.org/1999/xhtml">

  <ui:define name="subTitle">
    :: #{lbls.newEntry}   </ui:define>

  <ui:define name="content">
    <p:panel rendered="#{current.loggedIn}" header="#{lbls.newEntry}" >
      <h:form id="frmEntry">
        <h:panelGrid columns="3">

          <h:panelGroup>
            <h:outputLabel for="title" value="#{lbls.title}:"/>
            <p:focus for="title"/>
          </h:panelGroup>
          <p:inputText id="title" value="#{entry.passwordEntry.title}" maxlength="100" label="#{lbls.title}" required="true"/>
          <p:message for="title"/>

          <h:outputLabel for="description" value="#{lbls.description}:"/>
          <p:inputTextarea id="description" value="#{entry.passwordEntry.description}" maxlength="500" rows="3" cols="40" label="#{lbls.description}"/>
          <p:message for="description"/>

          <p:spacer height="10"/>
          <p:spacer height="10"/>
          <p:spacer height="10"/>

          <h:outputLabel for="username" value="#{lbls.username}:"/>
          <p:inputText id="username" value="#{entry.passwordEntry.username}" maxlength="100" label="#{lbls.username}"/>
          <p:message for="username"/>          

          <h:outputLabel for="password" id="lblPassword" value="#{lbls.password}:"  styleClass="#{entry.showPasswords ? 'none' : ''}" />  
          <p:password id="password" feedback="true" value="#{entry.passwordEntry.password}" match="conPassword" maxlength="100" 
                      label="#{lbls.password}" promptLabel="#{lbls.strengthPromp}" weakLabel="#{lbls.weakPassword}"  
                      goodLabel="#{lbls.goodPassword}" strongLabel="#{lbls.strongPassword}" styleClass="#{entry.showPasswords ? 'none' : ''}"
                      />
          <p:message id="msgPassword" for="password" class="#{entry.showPasswords ? 'none' : ''}"/>

          <h:outputLabel id="lblConPassword" for="conPassword" value="#{lbls.conPassword}:"
                         styleClass="#{entry.showPasswords ? 'none' : ''}"/>  
          <p:password id="conPassword" value="#{entry.passwordEntry.password}" label="#{lbls.conPassword}" maxlength="100"
                      styleClass="#{entry.showPasswords ? 'none' : ''}"/>
          <p:message id="msgConPassword" for="conPassword" class="display: #{!entry.showPasswords ? 'none' : ''}"/>

          <h:outputLabel id="lblPasswordV" for="passwordV" value="#{lbls.password}:" 
                         styleClass="#{!entry.showPasswords ? 'none' : ''}"/>  
          <p:inputText id="passwordV" value="#{entry.passwordEntry.password}"  maxlength="100" 
                       label="#{lbls.password}" 
                       styleClass="#{!entry.showPasswords ? 'none' : ''}"/>
          <p:message id="msgPasswordV" for="passwordV" 
                     class="#{!entry.showPasswords ? 'none' : ''}"/>

          <h:outputLabel for="showPasswords" value="#{lbls.showPasswords}:"/>
          <p:selectBooleanCheckbox id="showPasswords" label="#{lbls.showPasswords}" value="#{entry.showPasswords}">  
            <p:ajax process="password passwordV conPassword" update="password passwordV conPassword lblPassword lblPasswordV lblConPassword msgPassword msgConPassword msgPasswordV"/>
          </p:selectBooleanCheckbox>
          <h:outputText/>

          <p:spacer height="10"/>
          <p:spacer height="10"/>
          <p:spacer height="10"/>

          <h:outputLabel for="url" value="#{lbls.url}:"/>
          <p:inputText id="url" value="#{entry.passwordEntry.url}" maxlength="255" label="#{lbls.url}"/>
          <p:message for="url"/>

          <h:outputLabel for="ip" value="#{lbls.ip}:"/>
          <p:inputText id="ip" value="#{entry.passwordEntry.ip}" maxlength="255" label="#{lbls.ip}"/>
          <p:message for="ip"/>

          <p:spacer height="10"/>
          <p:spacer height="10"/>
          <p:spacer height="10"/>

          <h:outputLabel for="tags" value="#{lbls.tags}:"/>
          <p:autoComplete id="tags" value="#{entry.selectedTags}" 
                          completeMethod="#{entry.selectTag}" converter="PasswordEntry" multiple="true"
                          var="tag" itemLabel="#{tag.title}" itemValue="#{tag}" />  
          <p:message for="tags"/>

          <p:spacer height="10"/>
          <p:spacer height="10"/>
          <p:spacer height="10"/>

          <h:outputText/>
          <h:panelGroup layout="block" styleClass="right-align">
            <p:commandButton value="#{lbls.save}" actionListener="#{entry.save(event)}" 
                             update=":growl messages"/>
          </h:panelGroup>


          <f:facet name="footer">
            <p:messages id="messages"/>
          </f:facet>
        </h:panelGrid>
      </h:form>
    </p:panel>

    <ui:include src="/templates/not_logged_in.xhtml" rendered="!#{current.loggedIn}"/>   </ui:define>

</ui:composition>

and Bean:

package package;


@ManagedBean(name = "entry")
@ViewScoped
public class PasswordEntryBean implements Serializable {

  //<editor-fold defaultstate="collapsed" desc="FIELDS">   
  private static final Logger logger = LogUtil.getLogger(PasswordEntryBean.class);
  private PasswordEntry passwordEntry;
  @ManagedProperty(value = "#{current}")
  private CurrentSessionBean current;
  private Database database;
  private List<PasswordTag> selectedTags = new ArrayList<PasswordTag>();
  private Set<PasswordTag> tags;
  private boolean showPasswords;
  //</editor-fold>  

  //<editor-fold defaultstate="collapsed" desc="CONSTRUCTORS">    
  public PasswordEntryBean() {
    passwordEntry = new PasswordEntry();
  }

  @PostConstruct
  public void init() {
  }
  //</editor-fold>

  //<editor-fold defaultstate="collapsed" desc="PROPERTIES">    
  public PasswordEntry getPasswordEntry() {
    return passwordEntry;
  }

  public Database getDatabase() {
    return database;
  }

  public boolean getShowPasswords() {
    return showPasswords;
  }

  public void setShowPasswords(boolean showPasswords) {
    this.showPasswords = showPasswords;
  }

  public void setDatabase(Database database) {
    this.database = database;
  }

  public Set<PasswordTag> getTags() {
    return tags;
  }

  public void setTags(Set<PasswordTag> tags) {
    this.tags = tags;
  }

  public List<PasswordTag> getSelectedTags() {
    return selectedTags;
  }

  public void setSelectedTags(List<PasswordTag> selectedTags) {
    this.selectedTags = selectedTags;
  }

  public void setPasswordEntry(PasswordEntry passwordEntry) {
    this.passwordEntry = passwordEntry;
  }

  public CurrentSessionBean getCurrent() {
    return current;
  }

  public void setCurrent(CurrentSessionBean current) {
    this.current = current;
  }
  //</editor-fold>
}

UPDATED CODE


I just wrote a simpler code in order to make it easier for you to understand my problem:

JSF:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
    <title>Facelet Title</title>
    <style type="text/css">
      .none {
        display: none;
      }
    </style>
  </h:head>
  <h:body>
    <h1>Register</h1>
    <h:form id="frmRegistration">
      <h:panelGrid columns="3">
        <h:outputLabel value="Username:" for="username"/>
        <p:inputText label="username" id="username" value="#{testBean.username}" required="true"/>
        <p:message for="username"/>

        <h:outputLabel value="Password:" id="lblPassword" for="password" styleClass="#{!testBean.visiblePassword ? '' : 'none'}"/>
        <p:password label="password" id="password" value="#{testBean.password}" 
                        styleClass="#{!testBean.visiblePassword ? '' : 'none'}"/>
        <p:message for="password" id="msgPassword" class="#{!testBean.visiblePassword ? '' : 'none'}"/>

        <h:outputLabel value="Confirm Password:" id="lblCpassword" for="cpassword" styleClass="#{!testBean.visiblePassword ? '' : 'none'}"/>
        <p:password label="confirm password" id="cpassword" value="#{testBean.password}" 
                        styleClass="#{!testBean.visiblePassword ? '' : 'none'}"/>
        <p:message for="cpassword" id="msgCpassword" class="#{!testBean.visiblePassword ? '' : 'none'}"/>

        <h:outputLabel value="Password:" id="lblVpassword" for="vpassword" styleClass="#{testBean.visiblePassword ? '' : 'none'}"/>
        <p:inputText label="password" id="vpassword" value="#{testBean.password}" 
                        styleClass="#{testBean.visiblePassword ? '' : 'none'}"/>
        <p:message for="vpassword" id="msgVpassword" class="#{testBean.visiblePassword ? '' : 'none'}"/>

        <h:outputLabel value="Show password"/>
        <p:selectBooleanButton value="#{testBean.visiblePassword}" 
                               onLabel="Yes" offLabel="No">
          <p:ajax update="messages password cpassword vpassword lblPassword lblCpassword lblVpassword msgPassword msgCpassword msgVpassword"
                   process="messages password cpassword vpassword" listener="#{testBean.addMessage}" />
        </p:selectBooleanButton>


        <f:facet name="footer">
          <p:commandButton actionListener="#{testBean.save(event)}" value="Save" update="messages"/>
          <p:messages id="messages"/>
        </f:facet>
      </h:panelGrid>
    </h:form>
  </h:body>
</html>

AND BEAN:

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;

@ManagedBean
@ViewScoped
public class TestBean {

  private String username;
  private String password;
  private boolean visiblePassword;

  public void addMessage() {
    String summary = visiblePassword ? "Checked" : "Unchecked";

    FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(summary));
  }

  public TestBean() {
  }

  public void save(ActionEvent event) {
  }

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public boolean isVisiblePassword() {
    return visiblePassword;
  }

  public void setVisiblePassword(boolean visiblePassword) {
    this.visiblePassword = visiblePassword;
  }
}

This code can hide two fields and show the third field properly if I do not add process attribute to the <p:ajax tag. But this attribute is needed in order to these fields keep their values when the user switches between two modes (2 secret fields / 1 plain text field)

But it fails!

==========================================================

SECOND UPDATE

I used redisplay and the problem of empty values solved but still the inputs don't hide/show unless I set the update and process to @form which is not good for my case.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://java.sun.com/jsf/core">
  <h:head>
    <title>Facelet Title</title>
    <style type="text/css">
      .none {
        display: none;
      }
    </style>
  </h:head>
  <h:body>
    <h1>Register</h1>
    <h:form id="frmRegistration">
      <h:panelGrid columns="3">
        <h:outputLabel value="Username:" for="username"/>
        <p:inputText label="username" id="username" value="#{testBean.username}" required="true"/>
        <p:message for="username"/>

        <h:outputLabel value="Password:" id="lblPassword" for="password" rendered="#{!testBean.visiblePassword}"/>
        <p:password redisplay="true" label="password" id="password" value="#{testBean.password}" 
                        rendered="#{!testBean.visiblePassword}"/>
        <p:message for="password" id="msgPassword" rendered="#{!testBean.visiblePassword}"/>

        <h:outputLabel value="Confirm Password:" id="lblCpassword" for="cpassword" rendered="#{!testBean.visiblePassword}"/>
        <p:password redisplay="true" label="confirm password" id="cpassword" value="#{testBean.password}" 
                        rendered="#{!testBean.visiblePassword}"/>
        <p:message for="cpassword" id="msgCpassword" rendered="#{!testBean.visiblePassword}"/>

        <h:outputLabel value="Password:" id="lblVpassword" for="vpassword" rendered="#{testBean.visiblePassword}"/>
        <p:inputText label="password" id="vpassword" value="#{testBean.password}" 
                        rendered="#{testBean.visiblePassword}"/>
        <p:message for="vpassword" id="msgVpassword" rendered="#{testBean.visiblePassword}"/>

        <h:outputLabel value="Show password"/>
        <p:selectBooleanButton value="#{testBean.visiblePassword}" 
                               onLabel="Yes" offLabel="No">
          <p:ajax update="messages password cpassword vpassword lblPassword lblCpassword lblVpassword msgPassword msgCpassword msgVpassword"
                   process="password cpassword vpassword" listener="#{testBean.addMessage}" />
        </p:selectBooleanButton>


        <f:facet name="footer">
          <p:commandButton actionListener="#{testBean.save(event)}" value="Save" update="messages"/>
          <p:messages id="messages"/>
        </f:facet>
      </h:panelGrid>
    </h:form>
  </h:body>
</html>
2

2 Answers

1
votes

Your main mistake is that you're toggling visibility of the input fields using CSS in the client side, not using JSF in the server side. So JSF basically never knows which one is shown/hidden. All it knows is that both fields are shown. So it will process the both fields. As you've bound the value of the both fields to the one and same property, it will always end up getting the value of the last processed field.

You need to show/hide the input fields using JSF in the server side instead. You can use the therefor provided rendered attribute.

rendered="#{testBean.visiblePassword}"
1
votes

The problem is that you're binding the same variable entry.passwordEntry.password to 2 or more fields, so when submitting the <h:form> only one of the values in those fields will be set to entry.passwordEntry.password, the other values will be discarded.

The best way to solve this will be to have different variables for every field you have/need on the form. By looking at your code, it looks like that can be achieved by having 3 PasswordEntry attributes in your bean:

@ManagedBean(name = "entry")
@ViewScoped
public class PasswordEntryBean implements Serializable {
    //other attributes...
    private PasswordEntry passwordEntry;
    private PasswordEntry passwordEntryV;
    private PasswordEntry conPasswordEntry;

    //<editor-fold defaultstate="collapsed" desc="CONSTRUCTORS">    
    public PasswordEntryBean() {
        passwordEntry = new PasswordEntry();
        passwordEntryV = new PasswordEntry();
        conPasswordEntry = new PasswordEntry();
    }

    //getters and setters...
}

JSF Code:

<p:password id="password" feedback="true" value="#{entry.passwordEntry.password}"
    match="conPassword" maxlength="100" label="#{lbls.password}"
    promptLabel="#{lbls.strengthPromp}" weakLabel="#{lbls.weakPassword}"
    goodLabel="#{lbls.goodPassword}" strongLabel="#{lbls.strongPassword}"
    styleClass="#{entry.showPasswords ? 'none' : ''}" />

<p:password id="conPassword" value="#{entry.conPasswordEntry.password}"
    label="#{lbls.conPassword}" maxlength="100"
    styleClass="#{entry.showPasswords ? 'none' : ''}"/>

<p:inputText id="passwordV" value="#{entry.passwordEntryV.password}"
    maxlength="100" label="#{lbls.password}"
    styleClass="#{!entry.showPasswords ? 'none' : ''}"/>

If you want/need to have the same value in 2 or 3 places, you have to take into account that the bindings should not be in the same <h:form>, otherwise you will have the same problem. You can synchronize the variable values using plain JavaScript (after all, the <p:password> will be <input type="password"> and <p:input> will be <input type="text">) or in the server side when executing an action i.e. the listener that should be executed when selecting a value in your <p:selectBooleanCheckbox>.