9 Replies Latest reply on Jan 28, 2008 3:01 PM by Felix Khazin

    listShuttle looses value after validation error

    Lydia Ares Newbie

      I wanted to use the new listShuttle component and noticed the following strange behaviour:
      I have a form with one text input and one listShuttle. Both inputs are bound to values of my model object ("person"). I use the <s:validate /> tag to apply validation to the text input. If such a validation error occurs the page gets redisplayed (standard JSF behaviour). The thing is that after redisplaying the form, the listShuttle somehow looses its selected values although this is not immediately "visible" (because the selected values are still displayed). But when I correct the invalid text field input and submit the form again (no more validation errors), the selected values from the listShuttle do NOT get applied to my model object (see debug statement).
      What do I have to do? Is the listShuttle not a usable like other jsf inputs? Is more code necessary in the backing bean?
      Here is my code and thanks for any tip.

      person.xhtml:

      <?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:f="http://java.sun.com/jsf/core"
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:c="http://java.sun.com/jstl/core"
       xmlns:ui="http://java.sun.com/jsf/facelets"
       xmlns:s="http://jboss.com/products/seam/taglib"
       xmlns:a4j="http://richfaces.org/a4j"
       xmlns:rich="http://richfaces.org/rich">
      
      <ui:composition template="../layout.xhtml">
      
       <ui:define name="content">
      
       <h:messages />
      
       <h:form id="editForm">
      
       <div>
       <h:outputLabel value="#{messages['edit.person.name']}" for="personNameInput" />
       <h:inputText id="personNameInput" value="#{person.name}" required="true" >
       <s:validate />
       </h:inputText>
       </div>
      
       <div>
       <rich:panel id="listShuttlePanel">
       <rich:listShuttle
       listHeight="400" listWidth="400"
       sourceValue="#{editAction.availableRoles}"
       targetValue="#{person.roles}"
       sourceCaptionLabel="Available roles"
       targetCaptionLabel="Currently selected roles"
       converter="roleConverter"
       var="role">
      
       <rich:column>
       <h:outputText value="#{role.name}" ></h:outputText>
       </rich:column>
       </rich:listShuttle>
       </rich:panel>
       </div>
      
      
       <div>
       <h:panelGroup>
       <h:commandButton id="save" action="#{editAction.save}" value="#{messages.save}" />
       </h:panelGroup>
       </div>
      
       </h:form>
      
       </ui:define>
      
      </ui:composition>
      </html>
      


      EditAction.java:
      package example;
      
      import java.util.ArrayList;
      import java.util.List;
      
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.Logger;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.log.Log;
      
      @Name("editAction")
      public class EditAction {
      
       @Logger
       private Log logger;
      
       @In(create=true)
       private Person person;
      
       private List<Role> availableRoles;
      
       public List<Role> getAvailableRoles() {
       logger.info("++++ getAvailableRoles called ++++");
       if (availableRoles == null) {
       logger.info("++++++ initializing availableRoles list ++++");
       availableRoles = new ArrayList<Role>();
       availableRoles.add(new Role("guest", "Guest user"));
       availableRoles.add(new Role("user", "Normal user"));
       availableRoles.add(new Role("admin", "Administrator"));
       }
       return availableRoles;
       }
      
       public void setAvailableRoles(List<Role> availableRoles) {
       logger.info("++++ setAvailableRoles called ++++");
       this.availableRoles = availableRoles;
       }
      
       public String save() {
       logger.info("+++ saving person '" + person.getName() + "'");
       logger.info("+++ selected roles :");
       if (person != null && person.getRoles() != null) {
       for (Role role : person.getRoles()) {
       logger.info(role.getName());
       }
       }
       return "/edit/success.xhtml";
       }
      }
      


      Person.java:
      package example;
      
      import java.util.List;
      
      import org.hibernate.validator.NotEmpty;
      import org.jboss.seam.annotations.Name;
      
      @Name("person")
      public class Person {
      
       @NotEmpty
       private String Name;
      
       private List<Role> roles;
      
       public List<Role> getRoles() {
       return roles;
       }
      
       public void setRoles(List<Role> roles) {
       this.roles = roles;
       }
      
       public String getName() {
       return Name;
       }
      
       public void setName(String name) {
       Name = name;
       }
      
      }
      


      Role.java:
      package example;
      
      
      public class Role {
      
       private String id;
      
       private String name;
      
       public Role(String id, String name) {
       this.id = id;
       this.name = name;
       }
      
       public String getId() {
       return id;
       }
      
       public void setId(String id) {
       this.id = id;
       }
      
       public String getName() {
       return name;
       }
      
       public void setName(String name) {
       this.name = name;
       }
      
       public boolean equals(Object other) {
       if ( (this == other ) ) return true;
       if ( (other == null ) ) return false;
       if ( !(other instanceof Role) ) return false;
       Role castOther = ( Role ) other;
       return (this.getId().equals(castOther.getId()));
       }
      
       public int hashCode() {
       return getId() == null ? 0 : getId().hashCode();
       }
      
      }
      


      RoleConverter.java:
      package example;
      
      import javax.faces.component.UIComponent;
      import javax.faces.context.FacesContext;
      import javax.faces.convert.Converter;
      
      public class RoleConverter implements Converter {
      
       public static final String SEPARATOR = "@";
      
       public Object getAsObject(FacesContext context, UIComponent ui, String str) {
       int splitIndex = str.indexOf(SEPARATOR);
       String roleId = str.substring(0, splitIndex);
       String roleName = str.substring(splitIndex + 1);
       return new Role(roleId, roleName);
       }
      
       public String getAsString(FacesContext context, UIComponent ui, Object obj) {
       Role role = (Role) obj;
       return role.getId() + SEPARATOR + role.getName();
       }
      
      }