7 Replies Latest reply on Nov 26, 2009 1:37 PM by vdeminico

    selectOneMenu and a4j:support problem

    vdeminico

      Hi,
      I have a problem using the a4j support tag... I have a selectOneMenu in which there is a list of Regione objects. I'd want handle an onchange event doing something on the serverside (e.g. loading a list of objects into another selectOneMenu).


      The xhtml code is:



      <s:decorate id="valueDecoration1" template="layout/edit.xhtml">
          <ui:define name="label">
                 <h:outputLabel for="regioneSelect">Regione:</h:outputLabel>
          </ui:define>
          <h:selectOneMenu id="regioneSelect" value="" require="true">
           <s:selectItems value="#{regioni}" var="reg"  label="#{reg.nome}"/>
           <a4j:support event="onchange" actionListener="#{regioneAction.selectProvincia}"                     reRender="provinciaSelect" bypassUpdates="false"/>
          </h:selectOneMenu>
      </s:decorate>
      



      and my action component is:



           public void selectProvincia(ActionEvent e)
           {
                ValueHolder input = (ValueHolder)e.getComponent().getParent();
                logger.info("Regione selected: " + input.getValue());
                provincie=new ArrayList<Provincia>();
                
           }
      



      The method input.getValue() return a String object and its value is com.bbhostels.registration.entity.Regione@9dfb04, so the object address of the selected object. I'd want the object selected (an instance of class Regione) or the object id. How can I solve the problem???


      Another question... could I use the @DataModelSelection mechanism to automatically retrieve the selected item??? I try it, but I receive always the first object of the list.


      Thanks,
      Valerio.




        • 1. Re: selectOneMenu and a4j:support problem
          tmalatinszki

          Hi Valerio,


          In Seam You should use s:convertEntity tag with h:selectOneMenu, here's an example:


          <h:selectOneMenu value="#{regioneAction.selectedRegione}">
            <s:selectItems value="#{regioni}" var="reg" label="#{reg.nome}"/>
            <a4j:support event="onchange" action="#{regioneAction.selectProvincia}"/>
            <s:convertEntity/>
          </h:selectOneMenu>



          In regioneAction bean:


          private Regione selectedRegione;
          
          // getters-setters and other stuffs
          
          public void selectProvincia(){
            logger.info("Regione selected: " + selectedRegione.getNome());
          }



          Regrettably @DataModelSelection is not working with h:selectOneMenu (as You experienced it always returns with the first element), but in this case You don't need it anyway.


          Regards,


          Tamas

          • 2. Re: selectOneMenu and a4j:support problem
            vdeminico

            Hi Tamas,
            here is my code:


            registration.xhtml



            <h:selectOneMenu id="regioneSelect" value="#{regioneAction.selectedRegione}" require="true">
                <s:selectItems value="#{regioni}" var="reg"  label="#{reg.nome}"/>
                <a4j:support event="onchange" action="#{regioneAction.selectProvincia}"      reRender="provinciaSelect"/>
                <s:convertEntity/>
            </h:selectOneMenu>
            



            and the action bean:




            @Name("regioneAction")
            public class RegioneAction {
                    @In
                    RegioneService regioneService;
                    
                    @In
                    ProvinciaService provinciaService;
                    
                    @Logger
                    Log logger;
                    
                    @DataModel(scope=ScopeType.PAGE)
                    @Out(required=false)
                    private List<Regione> regioni;
                    
                    Regione selectedRegione;
                    
                    @Out(required=false,scope=ScopeType.PAGE)
                    private List<Provincia> provincie=new ArrayList<Provincia>();
                    
                    @Factory(value="regioni")
                    public void retrieveAllRegioni()
                    {
                            regioni = regioneService.retrieveAllRegione();
                    }
                    
            
                    public void selectProvincia()
                    {
                            logger.info("Regione.name: " + selectedRegione);
                    }
            
                    //getters and setters
            
            



            it prints out this error:


            sourceId=registrationForm:valueDecoration1:regioneSelect[severity=(ERROR 2), summary=(value is not valid), detail=(value is not valid)]
            





            Why?


            Thanks,
            Valerio.



            • 3. Re: selectOneMenu and a4j:support problem
              tmalatinszki

              Hi Valerio,


              You have to override hashCode() and equals() methods in Regione entity.


              Check this post, they had the same issue with h:selectOneMenu.


              Regards,


              Tamas

              • 4. Re: selectOneMenu and a4j:support problem
                vdeminico

                Ok Tamas, I solved that problem... But now I have another one...


                I have implemented the equals() and hashcode() methods on the Entity classes. Now my code is this:


                action bean:


                @Name("regioneAction")
                public class RegioneAction {
                     @In
                     RegioneService regioneService;
                     
                     @In
                     ProvinciaService provinciaService;
                     
                     @Logger
                     Log logger;
                     
                     @DataModel(scope=ScopeType.PAGE)
                     @Out(required=false)
                     private List<Regione> regioni;
                     
                     Regione selectedRegione = new Regione();
                     
                     @Out(required=false,scope=ScopeType.PAGE)
                     private List<Provincia> provincie=new ArrayList<Provincia>();
                     
                     @Factory(value="regioni")
                     public void retrieveAllRegioni()
                     {
                          regioni = regioneService.retrieveAllRegione();
                     }
                     
                
                     public void selectProvincia()
                     {
                          if(selectedRegione!=null)
                          {
                               logger.info("Selected on regione combo... Regione.name: " +      selectedRegione.getNome());
                               provincie = provinciaService.retrieveProvincieForRegione(selectedRegione);
                          }
                          
                     }
                   }
                



                registration.xhtml:



                <s:decorate id="valueDecoration1" template="layout/edit.xhtml">
                  <ui:define name="label">
                       <h:outputLabel for="regioneSelect">Regione:</h:outputLabel>
                  </ui:define>
                  <h:selectOneMenu id="regioneSelect" value="#{regioneAction.selectedRegione}"   require="true">
                     <s:selectItems value="#{regioni}" var="reg"  label="#{reg.nome}" />
                     <a4j:support event="onchange" action="#{regioneAction.selectProvincia}" reRender="provinciaSelect" bypassUpdates="false" />
                     <s:convertEntity/>
                   </h:selectOneMenu>
                                    
                </s:decorate>
                            
                <s:decorate id="valueDecoration2" template="layout/edit.xhtml">
                   <ui:define name="label">
                           <h:outputLabel for="provinciaSelect">Provincia:</h:outputLabel>
                   </ui:define>
                   <h:selectOneMenu id="provinciaSelect" value="" require="true">
                     <s:selectItems value="#{provincie}" var="prov" label="#{prov.nome}"/>
                   </h:selectOneMenu>
                </s:decorate>
                



                It has a strange behavior... the first time I select a value on the regioneSelect it normally load the provincia select values... when I select a regione again, it prints out this exception:



                16:19:35,953 ERROR [ExceptionFilter] handling uncaught exception
                javax.servlet.ServletException
                     at javax.faces.webapp.FacesServlet.service(FacesServlet.java:256)
                     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
                     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                     at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
                     at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:85)
                     at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                     at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64)
                     at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                     at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
                     at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                     at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:141)
                     at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:281)
                     at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:60)
                     at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                     at org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58)
                     at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                     at org.jboss.seam.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:68)
                     at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
                     at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158)
                     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
                     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
                     at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
                     at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
                     at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433)
                     at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
                     at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
                     at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
                     at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
                     at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
                     at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
                     at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
                     at java.lang.Thread.run(Unknown Source)
                Caused by: java.util.NoSuchElementException
                     at javax.faces.component.SelectItemsIterator.next(SelectItemsIterator.java:117)
                     at javax.faces.component.SelectItemsIterator.next(SelectItemsIterator.java:144)
                     at javax.faces.component.SelectItemsIterator.next(SelectItemsIterator.java:49)
                     at javax.faces.component.UISelectOne.matchValue(UISelectOne.java:164)
                     at javax.faces.component.UISelectOne.validateValue(UISelectOne.java:137)
                     at javax.faces.component.UIInput.validate(UIInput.java:867)
                     at javax.faces.component.UIInput.executeValidate(UIInput.java:1065)
                     at javax.faces.component.UIInput.processValidators(UIInput.java:666)
                     at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1033)
                     at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1033)
                     at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1033)
                     at javax.faces.component.UIForm.processValidators(UIForm.java:229)
                     at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1033)
                     at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:662)
                     at org.ajax4jsf.component.AjaxViewRoot.access$201(AjaxViewRoot.java:57)
                     at org.ajax4jsf.component.AjaxViewRoot$3.invokeRoot(AjaxViewRoot.java:319)
                     at org.ajax4jsf.context.JsfOneOneInvoker.invokeOnRegionOrRoot(JsfOneOneInvoker.java:56)
                     at org.ajax4jsf.context.AjaxContextImpl.invokeOnRegionOrRoot(AjaxContextImpl.java:170)
                     at org.ajax4jsf.component.AjaxViewRoot.processValidators(AjaxViewRoot.java:333)
                     at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:100)
                     at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251)
                     at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117)
                     at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244)
                     ... 31 more
                



                Any ideas?????


                Thanks,
                Valerio.



                • 5. Re: selectOneMenu and a4j:support problem
                  tmalatinszki

                  Have You tried to modify provinciaSelect element the same way as regioneSelect (with definied value attribute and s:convertEntity tag)? Or, just for test: do You receive the error messages if You remove the full provinciaSelect tag from Your XHTML code?


                  Regards,


                  Tamas

                  • 6. Re: selectOneMenu and a4j:support problem
                    vdeminico

                    I don't know which could be the problem... maybe the list in the action was not the same on the new request... However I have solved considering regioni list as a simple class field, not a DataModel, the same for provincie. I access these property through the regioneAction seam component and now it works correctly.
                    This is my new regioneAction bean code:



                    
                    @Name("regioneAction")
                    @Scope(ScopeType.PAGE)
                    public class RegioneAction {
                         @In
                         RegioneService regioneService;
                         
                         @In
                         ProvinciaService provinciaService;
                         
                         @In
                         ComuneService comuneService;
                         
                         @Logger
                         Log logger;
                         
                         private List<Regione> regioni;
                         
                         private List<Provincia> provincie=new ArrayList<Provincia>();
                         
                         private List<Comune> comuni=new ArrayList<Comune>();
                         
                         Regione selectedRegione;
                         
                         Provincia selectedProvincia;
                         
                         
                         public void retrieveAllRegioni()
                         {
                              if(regioni==null)
                                   regioni = regioneService.retrieveAllRegione();
                         }
                         
                    
                         public void selectRegione()
                         {
                              if(selectedRegione!=null)
                              {
                                   logger.info("Selected on regione combo... Regione.name: " + selectedRegione.getNome());
                                   provincie=provinciaService.retrieveProvincieForRegione(selectedRegione);
                                   comuni.clear();
                              }
                              
                         }
                         
                         public void selectProvincia()
                         {
                              if(selectedRegione!=null)
                              {
                                   logger.info("Selected on provincia combo... Provincia.name: " + selectedProvincia.getNome());
                                   comuni=comuneService.retrieveComuniForProvincia(selectedProvincia);
                              }
                         }
                    
                         public Regione getSelectedRegione() {
                              return selectedRegione;
                         }
                    
                    
                         public void setSelectedRegione(Regione selectedRegione) {
                              this.selectedRegione = selectedRegione;
                         }
                    
                    
                         public List<Regione> getRegioni()
                         {
                              return this.regioni;
                         }
                         
                         public void setRegioni(List<Regione> reg)
                         {
                              this.regioni=reg;
                         }
                    
                    
                         public List<Provincia> getProvincie() {
                              return provincie;
                         }
                    
                    
                         public void setProvincie(List<Provincia> provincie) {
                              this.provincie = provincie;
                         }
                    
                    
                         public List<Comune> getComuni() {
                              return comuni;
                         }
                    
                    
                         public void setComuni(List<Comune> comuni) {
                              this.comuni = comuni;
                         }
                    
                    
                         public Provincia getSelectedProvincia() {
                              return selectedProvincia;
                         }
                    
                    
                         public void setSelectedProvincia(Provincia selectedProvincia) {
                              this.selectedProvincia = selectedProvincia;
                         }
                         
                         
                              
                         
                    }
                    
                    






                    Thanks for your support Tamas.
                    Valerio.

                    • 7. Re: selectOneMenu and a4j:support problem
                      vdeminico

                      Hi,
                      I note a strange behaviour in the code example as above...
                      The complete example provides three selectOneMenus that are dependent each other. The xhtml code is the following:




                      <s:decorate id="regioneSelectDecoration" template="layout/edit.xhtml">
                                      <ui:define name="label">
                                           <h:outputLabel for="regioneSelect">Regione:</h:outputLabel>
                                      </ui:define>
                                      <h:selectOneMenu id="regioneSelect" value="#{regioneAction.selectedRegione}" required="true" rendered="#{empty attivita.comune}">
                                               <s:selectItems value="#{regioneAction.regioni}" var="reg"  label="#{reg.nome}" noSelectionLabel="--Selezionare una regione--"/>
                                               <a4j:support event="onchange" action="#{regioneAction.selectRegione}" reRender="provinciaSelect,comuneSelect" bypassUpdates="false" ajaxSingle="true">
                                                    <s:conversationId value="#{conversation.id}"/>
                                               </a4j:support>
                                               <s:convertEntity/>
                                          </h:selectOneMenu>
                                          <h:outputText value="#{attivita.comune.provincia.regione.nome}" rendered="#{not empty attivita.comune}" />
                                  </s:decorate>
                                  
                                  <s:decorate id="provinciaSelectDecoration" template="layout/edit.xhtml">
                                      <ui:define name="label">
                                           <h:outputLabel for="provinciaSelect">Provincia:</h:outputLabel>
                                      </ui:define>
                                      <h:selectOneMenu id="provinciaSelect" value="#{regioneAction.selectedProvincia}" required="true" rendered="#{empty attivita.comune}">
                                               <s:selectItems value="#{regioneAction.provincie}" var="prov" label="#{prov.nome}" noSelectionLabel="--Selezionare una provincia--"/>
                                               <a4j:support event="onchange" action="#{regioneAction.selectProvincia}" reRender="comuneSelect" bypassUpdates="false" ajaxSingle="true">
                                                    <s:conversationId value="#{conversation.id}"/>
                                               </a4j:support>
                                                <s:convertEntity />
                                          </h:selectOneMenu>
                                          <h:outputText value="#{attivita.comune.provincia.nome}" rendered="#{not empty attivita.comune}" />
                                  </s:decorate>
                                  
                                  <s:decorate id="comuneSelectDecoration" template="layout/edit.xhtml">
                                      <ui:define name="label">
                                           <h:outputLabel for="comuneSelect">Comune:</h:outputLabel>
                                      </ui:define>
                                      <h:selectOneMenu id="comuneSelect" value="#{attivita.comune}" required="true" rendered="#{empty attivita.comune}">
                                               <s:selectItems value="#{regioneAction.comuni}" var="com" label="#{com.nome}" noSelectionLabel="--Selezionare un comune--"/>
                                               <a4j:support event="onchange" action="#{regioneAction.selectComune()}" bypassUpdates="false" ajaxSingle="true">
                                                    <s:conversationId value="#{conversation.id}"/>
                                               </a4j:support>
                                                <s:convertEntity />
                                          </h:selectOneMenu>
                                          <h:outputText value="#{attivita.comune.nome}" rendered="#{not empty attivita.comune}" />
                                  </s:decorate>
                      



                      and the action class is:




                      public void selectRegione()
                           {
                                if(selectedRegione!=null)
                                {
                                     logger.info("Selected on regione combo... Regione.name: " + selectedRegione.getNome());
                                     provincie=provinciaService.retrieveProvincieForRegione(selectedRegione);
                                     comuni.clear();
                                }
                                
                           }
                           
                           /**Metodo che gestisce la selezione di una provincia e carica la lista dei comuni.
                            * 
                            */
                           public void selectProvincia()
                           {
                                if(selectedRegione!=null)
                                {
                                     logger.info("Selected on provincia combo... Provincia.name: " + selectedProvincia.getNome());
                                     comuni=comuneService.retrieveComuniForProvincia(selectedProvincia);
                                }
                           }
                           
                           public void selectComune()
                           {
                                if (selectedProvincia!=null)
                                {
                                     Attivita attivita = (Attivita) Component.getInstance(Attivita.class);
                                     selectedComune = attivita.getComune();
                                     logger.info("Selected on comune combo... Comune.name: " + selectedComune.getNome());
                                     logger.info("Retrieving Localita list for comune: " + selectedComune.getNome());
                                     listaLocalita = localitaService.retrieveLocalitaForComune(selectedComune); 
                                }
                           }
                      



                      it executes into a conversation, so I use a s:conversation into the a4j:support element. The problem is that if I select a Regione, then the Provincia is correctly updated. Same if I select a Provincia... it updates the Comune field. And if I select a different Regione or Provincia, it works fine updating the related fields. Then I select a Comune on the third field. When I do this operation, the onchange event on all select fields are not fired. So selecting a new item in Provincia doesn't fire any event (action method is not executed!). Why this behaviour??? Could it be a Seam 2.0.3 bug????


                      Thanks,
                      Valerio.