3 Replies Latest reply on Dec 18, 2008 4:21 PM by germanescobar

    listShuttle - how to change sourceValue

    captainvoid

      Hi,
      I have two listshuttles on my page, both with the same initial sourceValue. The targetValues are bound to properties of my model object.
      What I want to achieve is that the user cannot select the same value in both listShuttles.
      So I want to update the sourceValue of the second listShutttle if the user selects (or deselects) values in the first listShuttle and vice-versa.

      This is my page:

      <rich:tabPanel id="levelTabPanel"
       immediate="false"
       switchType="client">
      <rich:tab id="low"
       switchType="client"
       label="#{messages['authenticationMethodGroup.tab.low.title']}" >
       <rich:panel id="mechanismListLow"
       header="#{messages['authenticationMethodGroup.tabs.authNMechanisms.title']}">
       <rich:listShuttle id="methodShuttleLow"
       sourceValue="#{methodListController.availableMethods}"
       targetValue="#{refData.leveledGroupLow.authenticationMethods}"
       var="item"
       showButtonLabels="false"
       listHeight="300"
       listWidth="300"
       immediate="true"
       valueChangeListener="#{methodListController.methodSelected}"
       sourceCaptionLabel="#{messages['authenticationMethodGroup.tabs.authNMechanisms.available']}"
       targetCaptionLabel="#{messages['authenticationMethodGroup.tabs.authNMechanisms.selected']}"
       converter="#{refDataConverter}" >
       <rich:column>
       <a4j:outputPanel>
       <h:outputText value="#{item.description}"></h:outputText>
       <rich:toolTip
       mode="client"
       followMouse="true"
       showDelay="500"
       layout="block"
       value="#{item.id}" />
       </a4j:outputPanel>
       </rich:column>
       <a4j:support event="onlistchanged"
       ajaxSingle="true"
       immediate="true"
       bypassUpdates="true"
       reRender="methodShuttleLow, methodShuttleMedium" />
       </rich:listShuttle>
       </rich:panel>
      
      </rich:tab>
      <rich:tab id="medium"
       switchType="client"
       label="#{messages['authenticationMethodGroup.tab.medium.title']}" >
       <rich:panel id="mechanismListMedium"
       header="#{messages['authenticationMethodGroup.tabs.authNMechanisms.title']}">
       <rich:listShuttle id="methodShuttleMedium"
       sourceValue="#{methodListController.availableMethods}"
       targetValue="#{refData.leveledGroupMedium.authenticationMethods}"
       var="item"
       showButtonLabels="false"
       listHeight="300"
       listWidth="300"
       immediate="true"
       valueChangeListener="#{methodListController.methodSelected}"
       sourceCaptionLabel="#{messages['authenticationMethodGroup.tabs.authNMechanisms.available']}"
       targetCaptionLabel="#{messages['authenticationMethodGroup.tabs.authNMechanisms.selected']}"
       converter="#{refDataConverter}" >
       <rich:column>
       <a4j:outputPanel>
       <h:outputText value="#{item.description}"></h:outputText>
       <rich:toolTip
       mode="client"
       followMouse="true"
       showDelay="500"
       layout="block"
       value="#{item.id}" />
       </a4j:outputPanel>
       </rich:column>
       <a4j:support event="onlistchanged"
       ajaxSingle="true"
       immediate="true"
       bypassUpdates="true"
       reRender="methodShuttleLow, methodShuttleMedium" />
       </rich:listShuttle>
       </rich:panel>
      </rich:tab>
      </rich:tabPanel>
      


      my bean:

      @Name("methodListController")
      @Scope(ScopeType.PAGE)
      @AutoCreate
      public class MethodListController {
      
       @Logger
       private Log logger;
      
       private List<AuthenticationMethod> availableMethods;
      
       @Create
       public void init() {
       // initialize this.availableMethods
       // querying the database
       // ...
       logger.debug("-----> initialize availableMethods -> [#0]", availableMethods);
       }
      
       public List<AuthenticationMethod> getAvailableMethods() {
       logger.debug("-----> 'getAvailableMethods' called -> return [#0]", availableMethods);
       return availableMethods;
       }
      
       public void setAvailableMethods(List<AuthenticationMethod> availableMethods) {
       logger.debug("-----> 'setAvailableMethods' called [#0]", availableMethods);
       this.availableMethods = availableMethods;
       }
      
       /**
       * Value change listener for list shuttles 'methodShuttleLow'
       * and 'methodShuttleMedium' which updates this.availableMethods.
       *
       * @param event
       */
       @SuppressWarnings("unchecked")
       public void methodSelected(ValueChangeEvent event) {
       logger.debug("list shuttle value changed..");
       Object[] oldValue = (Object[]) event.getOldValue();
       Object[] newValue = (Object[]) event.getNewValue();
       List<AuthenticationMethod> oldAvailableValues = (List<AuthenticationMethod>) oldValue[0];
       logger.debug("oldAvailableMethods [#0]", oldAvailableValues);
       List<AuthenticationMethod> newAvailableValues = (List<AuthenticationMethod>) newValue[0];
       logger.debug("newAvailableMethods [#0]", newAvailableValues);
       if (oldAvailableValues.size() > newAvailableValues.size()) {
       // method(s) selected
       List<AuthenticationMethod> selectedMethods = new ArrayList<AuthenticationMethod>(oldAvailableValues);
       selectedMethods.removeAll(newAvailableValues);
       logger.debug("===> selectedMethods [#0]", selectedMethods);
       // update availableMethods
       availableMethods.removeAll(selectedMethods);
       }
       else {
       // method(s) deselected
       List<AuthenticationMethod> deselectedMethods = new ArrayList<AuthenticationMethod>(newAvailableValues);
       deselectedMethods.removeAll(oldAvailableValues);
       logger.debug("===> deselectedMethods [#0]", deselectedMethods);
       // update availableMethods
       availableMethods.addAll(deselectedMethods);
       }
       }
      
      }
      


      As you can see I'm using a ValueChangeListener which updates the available source values and the a4j:support rerenders both listShuttles.
      The problem is that this only works fine the first time. The second time something changes in one of the listShuttles, I get a "invalid value" validation error for a value that I added to the list of available source values. I know - equals/hashcode method and so on, but this is all implemented properly!
      What I think is that for changing the source value of a listShuttle something more has to be done and this is what I am missing here.
      I already tried with creating the list shuttles in Java (use binding) and then update the source value programmatically (htmlListShuttle.setSourceValue(), but no success, same error.
      Could somebody help me?