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

    Update issues with selectOneMenus using selectItems

    Richard Ogin Newbie

      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.

        • 2. Re: Update issues with selectOneMenus using selectItems
          Richard Ogin Newbie

          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
            Richard Ogin Newbie

            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
              Marcell Newbie

              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
                Richard Ogin Newbie

                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
                  Richard Ogin Newbie

                  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
                    Marcell Newbie

                    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?

                    • 10. Re: Update issues with selectOneMenus using selectItems
                      Andy Gibson Novice

                      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 Newbie

                        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
                          Richard Ogin Newbie

                          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
                            he youlin Novice

                            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
                              Richard Ogin Newbie

                              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.