14 Replies Latest reply on Jun 15, 2011 10:07 AM by gimpy21

    Update issues with selectOneMenus using selectItems

    gimpy21

      I have several selectOneMenus on a page using selectItems that get a List<String> from a conversation scoped bean. The problem I see is when calling an a4j:commandButton to remove a value from the selectOneMenu. All of the selectOneMenus in a different a4j:form (on the same page of course) that utilizes the same List<String> properly get updated but the selectOneMenu what was used to pull the selected item is not updated. The issue has been posted here under different guises:


      http://seamframework.org/Community/IssueWithSelectOneMenuAndA4j


      http://seamframework.org/Community/ProblemWithSelectOneMenuAndConversation


      http://seamframework.org/Community/DifferenceMyfacesAndRI


      I figure copy-paste code would be a waste but will gladly oblige if anyone thinks it would help.

        • 1. Re: Update issues with selectOneMenus using selectItems
          barbacena

          Post the code. It will help. :P

          • 2. Re: Update issues with selectOneMenus using selectItems
            gimpy21

            The bean is long so I'll post it separate.


            
            //imports
            
            @Stateful
            @Name("salesAreaCreator")
            @Scope(ScopeType.CONVERSATION)
            @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
            public class SalesAreaCreatorBean implements SalesAreaCreator, Serializable
            {
                 private static final String UNASSIGNED = "UNALLOCATED";
            
                 private List<String> log;
                 
                 @In(required=false)
                 private FacesMessages facesMessages;
                 
                 @In(create=true, required=false)
                 private List<String> states;
            
                 private List<String> counties;
            
                 @PersistenceContext
                 private Session session;
            
                 private String territoryName;
            
                 private String startRange;
                 private String endRange;
            
                 private List<String> sourceTerritories;
                 private String selectedRangeSourceTerritory;
                 private List<String> destinationTerritories;
                 private String selectedDestinationTerritory;
                 private String selectedSourceTerritory;
                 
                 private String selectedState;
                 private List<String> selectedCounties;
                 
                 private List<String> selectedStates;
            
                 private Map<String, Territory> territories;
                 
                 /**
                  * Updates available counties for given state.
                  * 
                  * Note: call this for BY COUNTY transfers only. BY STATE transfers do not need this.
                  * @return
                  */
                 
                 public String selectedStateChanged()
                 {
                      if(selectedState == null)
                           counties.clear();
                      else
                           updateAvailableCounties();
                      
                      selectedCounties = new ArrayList<String>(0);
                      
                      return null;
                 }
                 
                 private void updateAvailableCounties()
                 {
                      Query q = //query
                      
                      counties = (List<String>)q.list();
                 }
                 
                 private void updateLists()
                 {
                      sourceTerritories.clear();
                      destinationTerritories.clear();
                      
                      String[] names = territories.keySet().toArray(new String[]{});
                      Arrays.sort(names);
                      
                      Territory t = null;
                      for(String name : names)
                      {
                           t = territories.get(name);
                           if(t.count() > 0)
                                sourceTerritories.add(name);
                           
                           destinationTerritories.add(name);
                      }
                      
                      //we don't want to have them add items to UNASSIGNED
                      destinationTerritories.remove(UNASSIGNED);
                      
                      //move UNASSIGNED to top of the source list if it's in there
                      int index = sourceTerritories.indexOf(UNASSIGNED);
                      
                      if(index > 0) //it's in there and not at the top
                      {
                           sourceTerritories.remove(index);
                           sourceTerritories.add(0, UNASSIGNED);
                      }
                 }
                 
                 private boolean isValidZipCode(String s)
                 {
                      if(s == null || s.trim().length() != 5) return false;
                      
                      try
                      {
                           Integer.parseInt(s.trim());
                           return true;
                      }
                      catch(NumberFormatException e) { return false; }
                 }
                 
                 private List<String> getZipCodesInStates(List<String> states)
                 {
                      Query q = //query
                      
                      return (List<String>)q.list();
                 }
                 
                 private void logRangeTransfer(String source)
                 {
                      
                 }
                 
                 private void logStateTransfer(int zipCount)
                 {
                      
                 }
                 
                 private void logTerritoryTransfer(int zipCount)
                 {
                      
                 }
                 
                 private void logCountyTransfer(int zipCount)
                 {
                      
                 }
                 
                 public String transferByCounties()
                 {
                      if(selectedCounties.size() > 0)
                      {
                           List<String> zips = getZipCodesInCounties(selectedState, selectedCounties);
                           
                           transferZipCodeList(zips, selectedDestinationTerritory);
                      
                           updateLists();
                           
                           logCountyTransfer(zips.size());
                      }
                      else
                      {
                           facesMessages.add(FacesMessage.SEVERITY_ERROR, "No counties selected for transfer");
                      }
                      
                      return null;
                 }
                 
                 private List<String> getZipCodesInCounties(String state, List<String> counties)
                 {
                      Query q = //query
                      
                      return (List<String>)q.list();
                 }
                 
                 public String transferByTerritories()
                 {
                      if(selectedSourceTerritory != null)
                      {
                           if(selectedDestinationTerritory != null)
                           {
                                if(!selectedSourceTerritory.equals(selectedDestinationTerritory))
                                {
                                     Territory src = territories.get(selectedSourceTerritory);
                                     
                                     int count = src.count();
                                     
                                     src.transferZipCodes(territories.get(selectedDestinationTerritory));
                                     
                                     logTerritoryTransfer(count);
                                     
                                     updateLists();
                                }
                                else
                                {
                                     facesMessages.add(FacesMessage.SEVERITY_ERROR, "Source is also destination");
                                }
                           }
                           else
                           {
                                facesMessages.add(FacesMessage.SEVERITY_ERROR, "Destination territory not selected");
                           }
                      }
                      else
                      {
                           facesMessages.add(FacesMessage.SEVERITY_ERROR, "Source territory not selected");
                      }
                      
                      return null;
                 }
                 
                 public String transferByStates()
                 {
                      if(selectedStates.size() > 0)
                      {
                           List<String> zips = getZipCodesInStates(selectedStates);
                           
                           transferZipCodeList(zips, selectedDestinationTerritory);
                      
                           updateLists();
                           
                           logStateTransfer(zips.size());
                      }
                      else
                      {
                           facesMessages.add(FacesMessage.SEVERITY_ERROR, "No states selected for transfer");
                      }
                      
                      return null;
                 }
                 
                 /**
                  * Pulls all the listed zip codes from everyone and puts them in destination
                  * 
                  * @param zipCodes
                  * @param destination
                  */
                 
                 private void transferZipCodeList(List<String> zipCodes, String destination)
                 {
                      for(Territory t : territories.values())
                      {
                           if(t.getName().equals(destination))
                           {
                                t.add(zipCodes);
                           }
                           else
                           {
                                t.remove(zipCodes);
                           }
                      }
                 }
                 
                 /**
                  * selectedRangeSourceTerritory == null will pull from all
                  * @return
                  */
                 
                 public String transferByRange()
                 {
                      if(selectedDestinationTerritory != null)
                      {
                           if(selectedRangeSourceTerritory == null || !selectedRangeSourceTerritory.equals(selectedDestinationTerritory))
                           {
                                if( isValidZipCode(startRange) )
                                {
                                     if( isValidZipCode(endRange) )
                                     {
                                          int start = Integer.parseInt(startRange);
                                          int end = Integer.parseInt(endRange);
                                          
                                          if(start < end) //a range of zip codes
                                          {
                                               if(selectedRangeSourceTerritory == null) //a range of many to one transfers
                                               {
                                                    Territory destTer = territories.get(selectedDestinationTerritory);
                                                    for(Territory curTer : territories.values())
                                                    {
                                                         if(!curTer.getName().equals(selectedDestinationTerritory))
                                                         {
                                                              String curZip = null;
                                                              Iterator<String> iter = curTer.getCollectionIterator();
                                                              
                                                              while(iter.hasNext())
                                                              {
                                                                   curZip = iter.next();
                                                                   
                                                                   Integer i = Integer.parseInt(curZip);
                                                                   if(start <= i && i <= end)
                                                                   {
                                                                        iter.remove();
                                                                        destTer.add(curZip);
                                                                   }
                                                              }
                                                         }
                                                    }
                                               }
                                               else //a range of one to one transfers
                                               {
                                                    Territory from = territories.get(selectedRangeSourceTerritory);
                                                    Territory to = territories.get(selectedDestinationTerritory);
                                                    
                                                    String curZip = null;
                                                    Iterator<String> iter = from.getCollectionIterator();
                                                    
                                                    while(iter.hasNext())
                                                    {
                                                         curZip = iter.next();
                                                         
                                                         Integer i = Integer.parseInt(curZip);
                                                         if(start <= i && i <= end)
                                                         {
                                                              iter.remove();
                                                              to.add(curZip);
                                                         }
                                                    }
                                               }
                                               
                                               logRangeTransfer((selectedRangeSourceTerritory == null ? "ALL" : selectedRangeSourceTerritory));
                                          }
                                          else if (start == end) //single zip code transfer
                                          {
                                               for(Territory t : territories.values())
                                               {
                                                    t.remove(startRange);
                                               }
                                               
                                               territories.get(selectedDestinationTerritory).add(startRange);
                                               
                                               logRangeTransfer((selectedRangeSourceTerritory == null ? "ALL" : selectedRangeSourceTerritory));
                                          }
                                          else
                                          {
                                               facesMessages.add(FacesMessage.SEVERITY_ERROR, "Start zip code is larger than end zip code");
                                          }
                                     }
                                     else
                                     {
                                          facesMessages.add(FacesMessage.SEVERITY_ERROR, "Invalid end zip code");
                                     }
                                }
                                else
                                {
                                     facesMessages.add(FacesMessage.SEVERITY_ERROR, "Invalid start zip code");
                                }
                                
                                setStartRange(null);
                                setEndRange(null);
                           }
                           else
                           {
                                facesMessages.add(FacesMessage.SEVERITY_ERROR, "Source matches destination");
                           }
                      }
                      else
                      {
                           facesMessages.add(FacesMessage.SEVERITY_ERROR, "No destination selected");
                      }
                      
                      //TODO: move if called too often
                      updateLists();
                      
                      return null;
                 }
            
                 @Destroy
                 @Remove
                 public void destroy() { System.out.println("destroying salesAreaCreator");}
            
                 public String reset()
                 {
                      log.clear();
                      
                      counties.clear();
                      
                      selectedCounties = new ArrayList<String>();
                      selectedStates = new ArrayList<String>();
                      
                      territories.clear();
                      
                      Territory t = new Territory(UNASSIGNED);
                      t.add( getAllZipCodes() );
                      territories.put(t.getName(), t);
            
                      updateLists();
                      
                      return null;
                 }
                 
                 private List<String> getAllZipCodes() { return getZipCodesInStates(states); }
                 
                 @Begin(nested=true)
                 @Create
                 public void initialize()
                 {
                      sourceTerritories = new ArrayList<String>(0);
                      destinationTerritories = new ArrayList<String>(0);
                      
                      counties = new ArrayList<String>(0);
                      
                      territories = new HashMap<String,Territory>(0);
                      
                      log = new ArrayList<String>(0);
                      
                      reset();
                 }     
            
                 public void setTerritoryName(String name) { this.territoryName = name; }
                 
                 public String getTerritoryName() { return this.territoryName; }
            
                 public String addTerritory()
                 {
                      if (territoryName != null && territoryName.trim().length() != 0)
                      {
                           Territory t = new Territory(territoryName.trim().toUpperCase());
                           if (territories.containsKey(t.getName()))
                           {
                                
                                facesMessages.add(FacesMessage.SEVERITY_ERROR, "Territory name already exists");
                           }
                           else
                           {
                                territories.put(t.getName(), t);
                                updateLists();
                                log.add("Define sales area " + t.getName());
                           }
                      }
                      
                      setTerritoryName(null);
            
                      return null;
                 }
                 
                 /**
                  * Removes the territoryName
                  */
                 
                 public String removeTerritory()
                 {
                      if(territoryName != null && !territoryName.equals(UNASSIGNED)) // better safe than sorry
                      {
                           Territory toDelete = territories.get(territoryName);
                           
                           toDelete.transferZipCodes( territories.get(UNASSIGNED) );
                           
                           territories.remove(territoryName);
                           
                           updateLists();
                           
                           log.add("Remove sales area " + territoryName);
                      }
                      
                      setTerritoryName(null);
                      
                      return null;
                 }
            
            
                 public String getStartRange() { return startRange; }
            
                 public void setStartRange(String startRange) { this.startRange = startRange; }
            
                 public String getEndRange() { return endRange; }
            
                 public void setEndRange(String endRange) { this.endRange = endRange; }
            
                 public String getSelectedRangeSourceTerritory() { return selectedRangeSourceTerritory; }
            
                 public void setSelectedRangeSourceTerritory(String selectedRangeSourceTerritory) {
                      this.selectedRangeSourceTerritory = selectedRangeSourceTerritory;
                 }
            
                 public String getSelectedDestinationTerritory() { return selectedDestinationTerritory; }
            
                 public void setSelectedDestinationTerritory(String selectedDestinationTerritory) {
                      this.selectedDestinationTerritory = selectedDestinationTerritory;
                 }
            
                 public String getSelectedState() { return selectedState; }
            
                 public void setSelectedState(String selectedState) { this.selectedState = selectedState; }
            
                 public List<String> getSelectedCounties() { return selectedCounties; }
            
                 public void setSelectedCounties(List<String> selectedCounties) {
                      this.selectedCounties = selectedCounties;
                 }
            
                 public List<String> getStates() { return states; }
            
                 public List<String> getCounties() { return counties; }
            
                 public List<String> getSourceTerritories() { return sourceTerritories; }
            
                 public List<String> getDestinationTerritories() { return destinationTerritories; }
                 
                 public String verify()
                 {
                      String result = "valid";
                      
                      for(Territory t : territories.values())
                      {
                           if(t.getName().equals(UNASSIGNED))
                           {
                                if(t.count() != 0)
                                {
                                     facesMessages.add(FacesMessage.SEVERITY_ERROR, "There are unassigned zip codes");
                                     result = null;
                                     break;
                                }
                           }
                           else
                           {
                                if(t.count() == 0)
                                {
                                     facesMessages.add(FacesMessage.SEVERITY_ERROR, t.getName() + " does not contain zip codes");
                                     result = null;
                                     break;
                                }
                           }
                      }
                      
                      return result;
                 }
                 
                 private class Territory
                 {
                      private Collection<String> zipCodes;
                      private String name;
            
                      public Territory(String name)
                      {
                           this.name = name;
                           zipCodes = new TreeSet<String>();
                      }
            
                      public void transferZipCodes(Territory to)
                      {
                           to.add(zipCodes);
                           zipCodes.clear();
                      }
            
                      public String getName() { return this.name; }
            
                      public void add(Collection<String> zipCodes) { this.zipCodes.addAll(zipCodes); }
                      
                      public void remove(Collection<String> zipCodes) { this.zipCodes.removeAll(zipCodes); }
            
                      public void remove(String zipCode) { this.zipCodes.remove(zipCode); }
                      
                      public void add(String zipCode) { this.zipCodes.add(zipCode);     }
                      
                      public int count() { return this.zipCodes.size(); }
                      
                      public Iterator<String> getCollectionIterator() { return this.zipCodes.iterator(); }
            
                      /**
                       * equality is based on the name only
                       */
                      
                      public int hashCode() { return name.hashCode(); }
            
                      public boolean equals(Object o)
                      {
                           if (o == null || !(o instanceof Territory)) return false;
            
                           return this.hashCode() == o.hashCode();
                      }
                      
                      //we need this for the list sorting that we do
                      //public int compareTo(Territory other) { return this.name.compareTo(other.name); }
                 }
            
                 public List<String> getSelectedStates() { return selectedStates; }
            
                 public void setSelectedStates(List<String> selectedStates) { this.selectedStates = selectedStates; }
                 
                 public List<String> getLog() { return log; }
                 public int getUnassignedCount() { return territories.get(UNASSIGNED).count(); }
            
                 public String getSelectedSourceTerritory() { return selectedSourceTerritory; }
            
                 public void setSelectedSourceTerritory(String selectedSourceTerritory) {
                      this.selectedSourceTerritory = selectedSourceTerritory;
                 }
            }
            
            

            • 3. Re: Update issues with selectOneMenus using selectItems
              gimpy21

              Now for the page that uses it. The problem can be seen when using the Remove Territory panel.


              <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                              xmlns:s="http://jboss.com/products/seam/taglib"
                              xmlns:ui="http://java.sun.com/jsf/facelets"
                              xmlns:f="http://java.sun.com/jsf/core"
                              xmlns:h="http://java.sun.com/jsf/html"
                              xmlns:rich="http://richfaces.org/rich"
                              xmlns:a4j="http://richfaces.org/a4j">
              
                  <h2>Sales Areas</h2>
                  
                  <a4j:outputPanel ajaxRendered="true">
                       <a4j:form ajaxSubmit="true">
                           <a4j:region>
                               <rich:panel id="add_name">
                                   <f:facet name="header">Add Territory</f:facet>
                                     <h:panelGrid columns="3">
                                          <h:outputLabel value="Name"/>
                                         <h:inputText value="#{salesAreaCreator.territoryName}"/>
                                         <a4j:commandButton value="Add" action="#{salesAreaCreator.addTerritory}"
                                                            reRender="add_name, remove_name, tab_panel, unassigned_count_grid, error_panel"
                                                            eventsQueue="queue" ignoreDupResponses="true"
                                                            status="territory_status"/>
                                     </h:panelGrid>
                                </rich:panel>
                           </a4j:region>
                       </a4j:form>
                  </a4j:outputPanel>
                  
                  <a4j:outputPanel ajaxRendered="true">
                       <a4j:form ajaxSubmit="true">
                           <a4j:region>
                               <rich:panel id="remove_name" rendered="#{not empty salesAreaCreator.destinationTerritories}">
                                   <f:facet name="header">Remove Territory</f:facet>
                                     <h:panelGrid columns="3">
                                          <h:outputLabel value="Name"/>
                                         <h:selectOneMenu value="#{salesAreaCreator.territoryName}">
                                                   <s:selectItems value="#{salesAreaCreator.destinationTerritories}" var="dest" label="#{dest}"/>
                                               </h:selectOneMenu>
                                         <a4j:commandButton value="Remove" action="#{salesAreaCreator.removeTerritory}"
                                                            reRender="remove_name, tab_panel, unassigned_count_grid, error_panel"
                                                            eventsQueue="queue" ignoreDupResponses="true"
                                                            status="territory_status"/>
                                     </h:panelGrid>
                                </rich:panel>
                           </a4j:region>
                       </a4j:form>
                  </a4j:outputPanel>
                  
                  <h:panelGrid id="error_panel">
                      <h:messages/>
                  </h:panelGrid>
                  
                  <a4j:status forceId="true" id="territory_status" startText="Processing territory..."/>
                  <a4j:status forceId="true" id="transfer_status" startText="Transfering..."/>
                  <a4j:status forceId="true" id="update_status" startText="Updating..."/>
                  
                  <a4j:outputPanel ajaxRendered="true">
                           <rich:tabPanel id="tab_panel" switchType="ajax" rendered="#{not empty salesAreaCreator.destinationTerritories}">
                               
                                    <rich:tab id="state_tab" label="By State" eventsQueue="queue" ignoreDupResponses="true">
                                          <a4j:form ajaxSubmit="true">
                                               <a4j:region>
                                                    <rich:panel id="by_state_panel">
                                                         <h:selectManyListbox size="5" value="#{salesAreaCreator.selectedStates}">
                                                             <s:selectItems value="#{salesAreaCreator.states}" var="state" label="#{state}"/>
                                                         </h:selectManyListbox>
                                                         <h:selectOneMenu value="#{salesAreaCreator.selectedDestinationTerritory}">
                                                             <s:selectItems value="#{salesAreaCreator.destinationTerritories}" var="dest" label="#{dest}"/>
                                                         </h:selectOneMenu>
                                                         
                                                         <a4j:commandButton value="Transfer" action="#{salesAreaCreator.transferByStates}"
                                                                            reRender="tab_panel, error_panel"
                                                                            eventsQueue="queue" ignoreDupResponses="true"
                                                                            status="transfer_status"/>
                                                    </rich:panel>
                                               </a4j:region>
                                          </a4j:form>
                                     </rich:tab>
                                  
                                     <rich:tab id="county_tab" label="By County" eventsQueue="queue" ignoreDupResponses="true">
                                          <a4j:form ajaxSubmit="true">
                                              <h:selectOneMenu value="#{salesAreaCreator.selectedState}">
                                                   <s:selectItems value="#{salesAreaCreator.states}" var="state" label="#{state}"
                                                                  hideNoSelectionLabel="true"
                                                                  noSelectionLabel="Select..."/>
                                                   <a4j:support event="onchange" action="#{salesAreaCreator.selectedStateChanged}" reRender="county_tab, error_panel"
                                                                ajaxSingle="true" status="update_status"
                                                                eventsQueue="queue" ignoreDupResponses="true"/>
                                               </h:selectOneMenu>
                                               <h:selectManyListbox size="5" value="#{salesAreaCreator.selectedCounties}">
                                                   <s:selectItems value="#{salesAreaCreator.counties}" var="county" label="#{county}"/>
                                               </h:selectManyListbox>
                                               <h:selectOneMenu value="#{salesAreaCreator.selectedDestinationTerritory}">
                                                   <s:selectItems value="#{salesAreaCreator.destinationTerritories}" var="dest" label="#{dest}"/>
                                               </h:selectOneMenu>
                                               
                                               <a4j:commandButton value="Transfer" action="#{salesAreaCreator.transferByCounties}" reRender="tab_panel, error_panel"
                                                                  eventsQueue="queue" ignoreDupResponses="true"
                                                                  status="transfer_status"/>
                                          </a4j:form>
                                     </rich:tab>
                                
                                
                                  <rich:tab id="territory_tab" label="By Territory" eventsQueue="queue" ignoreDupResponses="true">
                                       <a4j:form ajaxSubmit="true">
                                            <h:selectOneMenu id="territy_source" value="#{salesAreaCreator.selectedSourceTerritory}">
                                                   <s:selectItems value="#{salesAreaCreator.sourceTerritories}" var="src" label="#{src}"/>
                                               </h:selectOneMenu>
                                               <h:selectOneMenu id="territory_destination" value="#{salesAreaCreator.selectedDestinationTerritory}">
                                                   <s:selectItems value="#{salesAreaCreator.destinationTerritories}" var="dest" label="#{dest}"/>
                                               </h:selectOneMenu>
                                            <a4j:commandButton value="Transfer" action="#{salesAreaCreator.transferByTerritories}" reRender="territory_tab, error_panel"
                                                               eventsQueue="queue" ignoreDupResponses="true" status="transfer_status"/>
                                       </a4j:form>
                                  </rich:tab>
                                
                                
                                     <rich:tab label="By Range" eventsQueue="queue" ignoreDupResponses="true">
                                          <a4j:form ajaxSubmit="true">
                                               <a4j:region>
                                                    <rich:panel id="range_panel">
                                                        <h:outputLabel value="Start"/>
                                                        <h:inputText value="#{salesAreaCreator.startRange}"/>
                                                        <h:outputLabel value="End"/>
                                                        <h:inputText value="#{salesAreaCreator.endRange}"/>
                                                        <h:selectOneMenu id="range_source" value="#{salesAreaCreator.selectedRangeSourceTerritory}">
                                                             <s:selectItems value="#{salesAreaCreator.sourceTerritories}" var="src" label="#{src}"
                                                                            noSelectionLabel="ALL"/>
                                                         </h:selectOneMenu>
                                                         <h:selectOneMenu id="range_destination" value="#{salesAreaCreator.selectedDestinationTerritory}">
                                                             <s:selectItems value="#{salesAreaCreator.destinationTerritories}" var="dest" label="#{dest}"/>
                                                         </h:selectOneMenu>
                                                         
                                                         <a4j:commandButton value="Transfer" action="#{salesAreaCreator.transferByRange}" reRender="tab_panel, error_panel"
                                                                            eventsQueue="queue" ignoreDupResponses="true" status="transfer_status"/>
                                                    </rich:panel>
                                               </a4j:region>
                                          </a4j:form>
                                     </rich:tab>
                           </rich:tabPanel>
                      </a4j:outputPanel>
                      
                      <a4j:outputPanel ajaxRendered="true">
                       <h:panelGrid id="unassigned_count_grid" columns="2" rendered="#{not empty salesAreaCreator.destinationTerritories}">
                           <h:outputLabel value="Zip codes currenty unassigned:"/>
                           <h:outputLabel value="#{salesAreaCreator.unassignedCount}"/>
                      </h:panelGrid>
                  </a4j:outputPanel>
                      
                      <a4j:outputPanel ajaxRendered="true">
                           <a4j:form ajaxSubmit="true">
                             <a4j:region>
                                     <rich:panel id="log_panel" rendered="#{not empty salesAreaCreator.log}">
                                         <f:facet name="header">Log</f:facet>
                                         <rich:dataList id="log_table" value="#{salesAreaCreator.log}" var="s">
                                        <rich:column>
                                            <h:outputText value="#{s}" />
                                        </rich:column>
                                    </rich:dataList>
                                     </rich:panel>
                                </a4j:region>
                           </a4j:form>
                      </a4j:outputPanel>
                      
                  <a4j:form ajaxSubmit="true">
                       <a4j:commandButton style="float:right" value="Next" action="#{salesAreaCreator.verify}"
                                          reRender="tab_panel, error_panel" immediate="true"
                                          eventsQueue="queue" ignoreDupResponses="true"
                                          ajaxSingle="true"/>
                      </a4j:form>
              </ui:composition>
              
              

              • 4. Re: Update issues with selectOneMenus using selectItems
                barbacena

                Your code is so big that I really don't have time to read all.


                However, from what I see you didn´t understand the use of <a4j:outputPanel ajaxRendered="true">, because you are still using reRender without limitToList property.


                After that, I can see optimizations (the use of regions). My advice is to not optimize until you get it working. Therefore, try to remove queues, regions, and everything that is optimization, until you get it working.


                Then read this.


                Sorry for not being able to point to the error, but I hope it helps.


                p.s.: if you can provide a simples example I would be able to help more. Have a look at: JBSEAM-2864

                • 5. Re: Update issues with selectOneMenus using selectItems
                  gimpy21

                  You're right, I didn't really understand that tag. I'll strip out everything and try again using what the link you provided states. Thanks for the quick reply.

                  • 6. Re: Update issues with selectOneMenus using selectItems
                    gimpy21

                    I stripped it down to a simple test case. It looks like I'm missing something fundamental in how JSF and Seam operate together. It removes from the list and returns the list of new values according to the debug prints, but the component is always one delete behind.


                    test.xhtml:


                    <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                                          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                    <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                                    xmlns:s="http://jboss.com/products/seam/taglib"
                                    xmlns:ui="http://java.sun.com/jsf/facelets"
                                    xmlns:h="http://java.sun.com/jsf/html"
                                    xmlns:a4j="http://richfaces.org/a4j">
                        
                        <a4j:outputPanel layout="none">
                             <a4j:form>
                                <h:outputLabel value="Select:"/>
                                <h:selectOneMenu value="#{test.selected}" id="menu">
                                        <s:selectItems value="#{test.values}" var="v" label="#{v}"/>
                                   </h:selectOneMenu>
                                <a4j:commandButton value="Remove" action="#{test.remove}" reRender="menu"/>
                             </a4j:form>
                        </a4j:outputPanel>
                        
                        <a4j:outputPanel ajaxRendered="true">
                             <h:messages/>
                        </a4j:outputPanel>
                        
                        <a4j:status startText="Processing..."/>
                    </ui:composition>
                    



                    testBean:


                    import javax.ejb.Remove;
                    import javax.ejb.Stateful;
                    
                    import org.jboss.seam.ScopeType;
                    import org.jboss.seam.annotations.Create;
                    import org.jboss.seam.annotations.Destroy;
                    import org.jboss.seam.annotations.Name;
                    import org.jboss.seam.annotations.Scope;
                    
                    @Stateful
                    @Name("test")
                    @Scope(ScopeType.SESSION)
                    public class TestBean implements Test, Serializable
                    {
                         private List<String> values;
                         private String selected;
                         
                         @Create
                         public void initialize()
                         {
                              System.out.println("initializing test bean");
                              values = new ArrayList<String>(5);
                              values.add("ALPHA");
                              values.add("BETA");
                              values.add("FOO");
                              values.add("BAR");
                              values.add("NIL");
                         }
                         
                         @Destroy
                         @Remove
                         public void destroy() {System.out.println("destroying test bean");}
                         
                         public String remove()
                         {
                              System.out.println("removing: " + selected);
                              values.remove(selected);
                              
                              setSelected(null);
                              
                              return null;
                         }
                    
                         public String getSelected() {
                              System.out.println("getSelected: " + selected);
                              return selected;
                         }
                    
                         public void setSelected(String selected) {
                              System.out.println("setSelected from " + this.selected + " to " + selected);
                              this.selected = selected;
                         }
                    
                         public List<String> getValues() {
                              System.out.println("getValues: " + values);
                              return values;
                         }
                    }
                    

                    • 7. Re: Update issues with selectOneMenus using selectItems
                      barbacena

                      I faced a problem like this, but with @Factory.


                      Could you try replacing the outputPanel with s:decorate id="menu" and removing the id definition from the selectOneMenu?

                      • 8. Re: Update issues with selectOneMenus using selectItems
                        gimpy21

                        It results in the same behavior.

                        • 9. Re: Update issues with selectOneMenus using selectItems
                          gimpy21

                          bump

                          • 10. Re: Update issues with selectOneMenus using selectItems
                            andygibson.contact.andygibson.net

                            Thanks for the shorter code that demonstrates the problem. I took out the ajax stuff from your example, and it appears that the problem remains even without throwing the complexities of AJAX in the mix.


                            I added a line :


                            <h:outputText value="Values : #{test.values}"/>
                            



                            To your page, and every time the list of values displayed there is correct. It seems the problem is with the drop down box lagging and I'm not sure why.


                            The model is re-bound to the control in the apply values part of the lifecycle before the application is invoked. Once the application is invoked and the item is removed from the list, it seems like this new list is never requsted from the bean by the component.


                            I combined your logging with my lifecycle phase listener and everything hits at the right times, with the following output :


                            Initial Page Render


                            15:57:34,593 DEBUG [LogPhaseListener] Executed Phase RESTORE_VIEW 1
                            15:57:34,640 INFO  [STDOUT] initializing test bean
                            15:57:34,640 INFO  [STDOUT] getSelected: null
                            15:57:34,640 INFO  [STDOUT] getValues: [ALPHA, BETA, FOO, BAR, NIL]
                            15:57:34,656 INFO  [STDOUT] getSelected: null
                            15:57:34,656 INFO  [STDOUT] getValues: [ALPHA, BETA, FOO, BAR, NIL]
                            15:57:34,656 INFO  [STDOUT] getSelected: null
                            15:57:34,656 INFO  [STDOUT] getSelected: null
                            15:57:34,656 INFO  [STDOUT] getSelected: null
                            15:57:34,656 INFO  [STDOUT] getSelected: null
                            15:57:34,656 INFO  [STDOUT] getSelected: null
                            15:57:34,656 INFO  [STDOUT] getSelected: null
                            15:57:34,656 DEBUG [LogPhaseListener] Execution Time = 63ms
                            15:57:34,656 DEBUG [LogPhaseListener] Executed Phase RENDER_RESPONSE 6
                            



                            then I deleted Beta


                            15:58:12,718 DEBUG [LogPhaseListener] Executed Phase RESTORE_VIEW 1
                            15:58:12,718 DEBUG [LogPhaseListener] Executed Phase APPLY_REQUEST_VALUES 2
                            15:58:12,718 INFO  [STDOUT] getSelected: null
                            15:58:12,718 INFO  [STDOUT] getValues: [ALPHA, BETA, FOO, BAR, NIL]
                            15:58:12,734 INFO  [STDOUT] getSelected: null
                            15:58:12,734 DEBUG [LogPhaseListener] Executed Phase PROCESS_VALIDATIONS 3
                            15:58:12,734 INFO  [STDOUT] setSelected from null to BETA
                            15:58:12,734 DEBUG [LogPhaseListener] Executed Phase UPDATE_MODEL_VALUES 4
                            15:58:12,734 INFO  [STDOUT] removing: BETA
                            15:58:12,734 INFO  [STDOUT] setSelected from BETA to null
                            15:58:12,734 DEBUG [LogPhaseListener] Executed Phase INVOKE_APPLICATION 5
                            15:58:12,750 INFO  [STDOUT] getSelected: null
                            15:58:12,750 INFO  [STDOUT] getValues: [ALPHA, FOO, BAR, NIL]
                            15:58:12,750 INFO  [STDOUT] getSelected: null
                            15:58:12,750 INFO  [STDOUT] getValues: [ALPHA, FOO, BAR, NIL]
                            15:58:12,750 INFO  [STDOUT] getSelected: null
                            15:58:12,750 INFO  [STDOUT] getSelected: null
                            15:58:12,765 INFO  [STDOUT] getSelected: null
                            15:58:12,765 INFO  [STDOUT] getSelected: null
                            15:58:12,765 INFO  [STDOUT] getSelected: null
                            15:58:12,765 INFO  [STDOUT] getSelected: null
                            15:58:12,765 DEBUG [LogPhaseListener] Execution Time = 47ms
                            15:58:12,765 DEBUG [LogPhaseListener] Executed Phase RENDER_RESPONSE 6
                            



                            This is really weird as it looks like the drop down is taking the values it gets from the apply request values phase and never getting an updated list on the render response phase after the invoke application phase which modified the list.


                            I added the following code to the remove item method to try and manually put the values in the drop down :


                            System.out.println("Manually setting values : "+getValues());
                            binding.getItems().setValue(getValues());
                            



                            Which gives us :


                            16:11:44,484 INFO  [STDOUT] removing: BAR
                            16:11:44,484 INFO  [STDOUT] setSelected from BAR to null
                            16:11:44,484 INFO  [STDOUT] getValues: [ALPHA, FOO, NIL]
                            16:11:44,484 INFO  [STDOUT] Manually setting values : [ALPHA, FOO, NIL]
                            16:11:44,484 INFO  [STDOUT] getValues: [ALPHA, FOO, NIL]
                            16:11:44,484 DEBUG [LogPhaseListener] Executed Phase INVOKE_APPLICATION 5
                            16:11:44,500 INFO  [STDOUT] getSelected: null
                            16:11:44,500 INFO  [STDOUT] getSelected: null
                            16:11:44,500 INFO  [STDOUT] getSelected: null
                            16:11:44,515 INFO  [STDOUT] getSelected: null
                            16:11:44,515 INFO  [STDOUT] getSelected: null
                            16:11:44,515 INFO  [STDOUT] getSelected: null
                            16:11:44,515 INFO  [STDOUT] getSelected: null
                            16:11:44,515 DEBUG [LogPhaseListener] Execution Time = 62ms
                            16:11:44,515 DEBUG [LogPhaseListener] Executed Phase RENDER_RESPONSE 6



                            We are removing the item, pushing the list into the drop down, and the control does not ask for the list again, so I have no idea how it is still keeping  the value in the drop down until the next time.


                            This may be a common problem, but I couldn't find an answer by some casual googling. I also tried using an actionListener as well, which gave the same results.





                            • 11. Re: Update issues with selectOneMenus using selectItems
                              ben_utzer

                              Has there been any news on this issue? I'm facing the same problem now. Any tipps or workarounds?


                              Regards,


                              Ben

                              • 12. Re: Update issues with selectOneMenus using selectItems
                                gimpy21

                                Hi Ben. I retested this today with Seam 2.2.1.CR1 and I still encounter the same problem. I also looked into the selectOneMenu source and couldn't find anything that stuck out as an immediate culprit. As far as a workaround, I think I used a RichFaces shuttleList.

                                • 13. Re: Update issues with selectOneMenus using selectItems
                                  alin.heyoulin.qq.com

                                  This may be a bug of reichfaces3. I test it on richfaces4 and work fine. Use my seam2jsf2


                                  • 14. Re: Update issues with selectOneMenus using selectItems
                                    gimpy21

                                    Andy tested with the AJAX components removed, so I don't think it's necessarily RichFaces specific. Does 'seam2jsf2' use JSF 2.x? If so, then I believe we found a useable solution.