1 2 Previous Next 18 Replies Latest reply on Nov 28, 2009 11:56 AM by notify

    Yet another problem with h:selectOneMenu value not changing

    notify

      I populate my drop down list with values from a table (of devices which I wish to track);


        <h:outputLabel for="devicesToTrack">Device to track</h:outputLabel>
                          <h:selectOneMenu value="#{selectedDeviceToTrack}" id="devicesToTrack" required="true">
                              <s:selectItems value="#{devicesToTrackList}" 
                                 var="devicesToTrack" 
                                 label="#{devicesToTrack.vehicleAllocatedTo}"
                                 noSelectionLabel="Please Select ..." />
                              <s:convertEntity/> 
                              <a4j:support event="onchange" action="#{piNPOiNTDeviceToTrackBean.getSelectedDeviceToTrack()}" reRender="NOTiFYPiNPOINTpanelGrid" />
                          </h:selectOneMenu> 
                          <rich:message for="devicesToTrack">
                          </rich:message>
      



      The drop down list has two entries in alpabetic order. When I change the value from the drop down the following code is executed;


       @In (required = false)
       private DevicesToTrack selectedDeviceToTrack;
      
       public final void getSelectedDeviceToTrack() {
          log.info(">>>>> getSelectedDeviceToTrack selectedDeviceToTrack = " + selectedDeviceToTrack.getVehicleAllocatedTo());
       }
      



      The value is always the first entry in the list no matter what I change the selection in the drop down list to!


      Any suggestions?

        • 1. Re: Yet another problem with h:selectOneMenu value not changing
          asookazian

          IIRC, it should be something like this (getter/setter needs to be invoked on a Seam component backing bean):


          <h:selectOneMenu value="#{foo.selectedDeviceToTrack}" id="devicesToTrack" required="true">



          ex: http://www.jsftoolbox.com/documentation/help/12-TagReference/html/h_selectOneMenu.html

          • 2. Re: Yet another problem with h:selectOneMenu value not changing
            notify

            I originally did that with;


            <h:selectOneMenu value="#{devicesToTrackBean.selectedDevicesToTrack}" id="devicesToTrack" required="true">
            



            which gives the error;


            javax.el.ELException: /map.xhtml @43,127 value="#{devicesToTrackBean.selectedDevicesToTrack}": 
            Error reading 'selectedDevicesToTrack' on type 
            org.javassist.tmp.java.lang.Object_$$_javassist_seam_3
            



            where as this works fine!


            <rich:calendar name="selectedDateFromCalendar" id="selectedDateFromCalendar" label="selectedDateFrom" 
            value="#{calendarBean.selectedDateFrom}" datePattern="#{calendarBean.pattern}" popup="true" >
            



            Have I totally misunderstood something about accessing a SLSB from Seam?

            • 3. Re: Yet another problem with h:selectOneMenu value not changing
              notify

              It is now working, but it still doesn't get the new value when the dropdown selection is changed.


              XHTML;


              <h:outputLabel for="devicesToTrack">Device to track</h:outputLabel>
                  <h:selectOneMenu value="#{piNPOiNTDevicesToTrackBean.selectedDevicesToTrack}" id="devicesToTrack" >
                      <s:selectItems value="#{devicesToTrackList}" 
                           var="devicesToTrack" 
                           label="#{devicesToTrack.vehicleAllocatedTo}" />
                       <s:convertEntity/> 
                       <a4j:support event="onchange" action="#{devicesToTrackBean.getDevicesToTrackCurrentLocation()}" reRender="NOTiFYPiNPOINTpanelGrid" />
                  </h:selectOneMenu> 
                  <rich:message for="devicesToTrack">
                  </rich:message>
              



              The SLSB;


               // @In attribute requires non-null value
                  @In (create=true, required=false)
                  // @Out attribute requires non-null value
                  @Out (required=false)
                  
                  // static didn't help
                  private DevicesToTrack selectedDevicesToTrack;
                  
                  /**
                   *
                   */
                   public PiNPOiNTDevicesToTrackBean() {
                  }
                  
                  @Remove @Destroy
                  public final void destroy() {}
                  
                  public void setSelectedDevicesToTrack(final DevicesToTrack selectedDevicesToTrack) {
                       log.info("***** set setSelectedDevicesToTrack");
                       this.selectedDevicesToTrack = selectedDevicesToTrack;
                       
                       if (selectedDevicesToTrack != null) {
                            log.info("***** set setSelectedDevicesToTrack selectedDevicesToTrack = " + selectedDevicesToTrack.getVehicleAllocatedTo());
                       }
                  }
              
                  public DevicesToTrack getSelectedDevicesToTrack() {
                       log.info(">>>>> get getSelectedDevicesToTrack");
                       
                       if (this.selectedDevicesToTrack != null) {
                            log.info(">>>>> get getSelectedDevicesToTrack selectedDevicesToTrack = " + this.selectedDevicesToTrack.getVehicleAllocatedTo());
                       }
                       
                       return this.selectedDevicesToTrack;
                  }
              



              If I change the drop down selection the event occurs and the SLSB is called but it is always the first value in the drop down that is passed!


              How do I ensure that the selected value is passed?


              Thanks.

              • 4. Re: Yet another problem with h:selectOneMenu value not changing
                asookazian

                have you looked to see how this is implemented in any of the Seam distro example projects?

                • 5. Re: Yet another problem with h:selectOneMenu value not changing
                  notify

                  Many .....


                  The example with Seam 2.2.0.GA: UI;


                  <h:selectOneMenu value="#{person.honorific}">
                      <s:selectItems value="#{honorifics}" var="honorific" label="#{honorific.label}" noSelectionLabel="Please select" />
                      <s:convertEnum />
                  </h:selectOneMenu>
                  



                  It uses an enum converter as the values are hardcoded in the action class;


                   public enum Honorific {
                        
                        MR("Mr."), 
                        MRS("Mrs."), 
                        MISS("Miss."), 
                        MS("Ms."),
                        DOCTOR("Dr.");
                        
                        private String label;
                        
                        Honorific(String label)
                        {
                           this.label = label;
                        }
                        
                        public String getLabel()
                        {
                           return label;
                        }      
                     }
                  



                  Whilst I dynamically build my list and use EntityConverter;


                  @SuppressWarnings("unchecked")
                  @Begin (join=true)
                  @Factory("devicesToTrackList")  
                  public final List getDevicesToTrack() {
                      log.info(">>>>> getDevicesToTrack credentials = " + credentials.getUsername());
                          
                      final Query query = entityManager.createQuery(GET_DEVICES_TO_TRACK);
                      query.setParameter(ONE, credentials.getUsername());
                          
                      devicesToTrackList = query.getResultList();
                      log.info(">>>>> getDevicesToTrack devicesToTrackList size = " + devicesToTrackList.size());
                                  
                      return devicesToTrackList;
                  }
                  



                  XHTML;


                  <h:outputLabel for="devicesToTrack">Device to track</h:outputLabel>
                                      <h:selectOneMenu value="#{piNPOiNTDevicesToTrackBean.selectedDevicesToTrack}" id="devicesToTrack" >
                                          <s:selectItems value="#{devicesToTrackList}" 
                                             var="devicesToTrack" 
                                             label="#{devicesToTrack.vehicleAllocatedTo}" />
                                          <s:convertEntity/> 
                                          <a4j:support event="onchange" action="#{devicesToTrackBean.getDevicesToTrackCurrentLocation()}" reRender="NOTiFYPiNPOINTpanelGrid" />
                                      </h:selectOneMenu> 
                                      <rich:message for="devicesToTrack">
                                      </rich:message>
                  



                  When I change the value on the drop down it calls my EJB in the XHTML by;


                  #{piNPOiNTDevicesToTrackBean.selectedDevicesToTrack}
                  



                  and which is this method in the EJB;


                  /**
                       *
                       * @return
                       */
                      public DevicesToTrack getSelectedDevicesToTrack() {
                          log.info(">>>>> get getSelectedDevicesToTrack");
                          
                          if (this.selectedDevicesToTrack != null) {
                                  log.info(">>>>> get getSelectedDevicesToTrack selectedDevicesToTrack = " + this.selectedDevicesToTrack.getVehicleAllocatedTo());
                          }
                          
                          return this.selectedDevicesToTrack;
                      }
                  



                  The JBoss console shows;


                  09:04:50,359 INFO  [DevicesToTrackBean] ***** 1 getDevicesToTrackCurrentLocation devicesToTrack = 07791*****
                  09:04:50,359 INFO  [PiNPOiNTDevicesToTrackBean] >>>>> get getSelectedDevicesToTrack
                  09:04:50,359 INFO  [PiNPOiNTDevicesToTrackBean] >>>>> get getSelectedDevicesToTrack selectedDevicesToTrack = Roger Lee 
                  09:04:50,359 INFO  [DevicesToTrackBean] ***** 2 getDevicesToTrackCurrentLocation devicesToTrack vehicleAllocatedTo = Roger Lee
                  



                  This is the first entry in my list. If I add a device to my table which comes before Roger Lee  (sorted alphabetically) it will be this device which always appears.


                  In a nutshell it appears that it always gets Entity element 0 in the list!


                  This is a total show stopper for my project.

                  • 6. Re: Yet another problem with h:selectOneMenu value not changing
                    notify

                    Really need some help on this one.


                    To try and isolate the problem I created a simple Facelet (XHTML) with just selectOneMenu component on the page;


                    <h:form id="testComponentForm">
                             <h:selectOneMenu value="#{piNPOiNTDevicesToTrackBean.selectedDevicesToTrack}" required="true"     id="selectedDevicesToTrack" >
                                 <s:selectItems value="#{devicesToTrackList}" var="devicesToTrack" label="#{devicesToTrack.vehicleAllocatedTo}" />
                                 <s:convertEntity/> 
                                 <a4j:support event="onchange" action="#{devicesToTrackBean.getDevicesToTrackTest()}" />
                             </h:selectOneMenu> 
                    </h:form>
                    



                    My basic SLSB;


                    @Stateful
                    @Name("piNPOiNTDevicesToTrackBean")
                    //@Interceptors(SeamInterceptor.class)
                    @JndiName("ejb/PiNPOiNTDevicesToTrackRemote")
                    @Scope(ScopeType.CONVERSATION)
                    public class PiNPOiNTDevicesToTrackBean implements PiNPOiNTDevicesToTrackRemote {
                    
                         private static final long serialVersionUID = 1L;
                    
                         @Logger
                         private Log log;
                    
                         @In (create = true, required = false)
                         @Out
                         private DevicesToTrack selectedDevicesToTrack;
                         
                         /**
                           *
                          */
                         public PiNPOiNTDevicesToTrackBean() {
                         }
                    
                         @Remove
                         @Destroy
                         public final void destroy() {
                         }
                    
                         /**
                          * 
                          * @param selectedDevicesToTrack
                          */
                         public void setSelectedDevicesToTrack(final DevicesToTrack _selectedDevicesToTrack) {
                              this.selectedDevicesToTrack = _selectedDevicesToTrack;
                    
                              if (selectedDevicesToTrack != null) {
                                   log.info("..... SET setSelectedDevicesToTrack selectedDevicesToTrack = " + this.selectedDevicesToTrack.getVehicleAllocatedTo());
                              }
                         }
                    
                         /**
                          * 
                          * @return
                          */
                         public DevicesToTrack getSelectedDevicesToTrack() {
                              if (this.selectedDevicesToTrack != null) {
                                   log.info("..... GET getSelectedDevicesToTrack selectedDevicesToTrack = " + this.selectedDevicesToTrack.getVehicleAllocatedTo());
                              }
                    
                              return this.selectedDevicesToTrack;
                         }
                    }
                    



                    When a different value is selected from the selectOneMenu the onchange action calls a method in another SLSB;


                     public final void getDevicesToTrackTest() {
                             log.info(">>>>> getDevicesToTrackTest " + this.selectedDevicesToTrack.getVehicleAllocatedTo());
                     }
                    



                    No matter what I select (or do to the code) it always selects the first entry (entity) from my list.


                    Surely other people create dynamic drop-down lists. I think I've Googles every post! I'd love some suggestions to try!

                    • 7. Re: Yet another problem with h:selectOneMenu value not changing
                      mrblacksmith

                       public final void getDevicesToTrackTest() {
                               log.info(">>>>> getDevicesToTrackTest " + this.selectedDevicesToTrack.getVehicleAllocatedTo());
                       }
                      




                      Try removing the final declarations on your methods. I made a few tests and it all worked fine, until I noticed the public final...test(). Adding that to my test case made it fail. I also tried setting my factory method to final (as you had in 'public final List getDevicesToTrack() ') and then my injected list was null thus it failed.


                      Any specific reason you have the methods declared final?

                      • 8. Re: Yet another problem with h:selectOneMenu value not changing
                        notify

                        Marcus Smedman wrote on Nov 26, 2009 18:32:



                         public final void getDevicesToTrackTest() {
                                 log.info(">>>>> getDevicesToTrackTest " + this.selectedDevicesToTrack.getVehicleAllocatedTo());
                         }
                        




                        Try removing the final declarations on your methods. I made a few tests and it all worked fine, until I noticed the public final...test(). Adding that to my test case made it fail. I also tried setting my factory method to final (as you had in 'public final List getDevicesToTrack() ') and then my injected list was null thus it failed.

                        Any specific reason you have the methods declared final?


                        Adding final - habit. CheckStyle always suggested it and it stops the method being overridden.


                        Tried you suggestion and afraid it didn't make any difference, I am still getting the first entry in the list.


                        Any chance of you posting your example that worked?


                        Thanks for your suggestion.

                        • 9. Re: Yet another problem with h:selectOneMenu value not changing
                          mrblacksmith

                          Sure.


                          xhtl:


                          <h:form>
                               <h:outputLabel>Person to track</h:outputLabel>
                               <h:selectOneMenu value="#{personAction.selectedPerson}" id="selectedPerson">
                                    <s:selectItems value="#{personsToTrack}" var="_person" label="#{_person.email}" />
                                    <s:convertEntity />
                                    <a:support event="onchange" action="#{personAction.test()}" />
                               </h:selectOneMenu>
                          </h:form></p>
                          




                          The interface:


                          @Local
                          public interface PersonAction {
                          
                               public Person getSelectedPerson();
                          
                               public void setSelectedPerson(Person person);
                          
                               public void test();
                          
                          }
                          



                          The action bean (personList is a seam-gen generated standard list for a Person entity):


                          @Scope(ScopeType.CONVERSATION)
                          @Name("personAction")
                          public class PersonActionBean implements PersonAction, Serializable {
                          
                               @In(create = true)
                               private PersonList personList;
                          
                               private List<Person> personsToTrack = new ArrayList<Person>();
                          
                               @Out
                               private Person selectedPerson = new Person();
                          
                               @Factory("personsToTrack")
                               public List<Person> initPersonsToTrack() {
                                        personsToTrack = personList.getResultList();
                                    System.out.println("initPersonsToTrack");
                                        return personsToTrack;
                               }
                          
                               @Override
                               public Person getSelectedPerson() {
                                    log.info(">>>>> get selectedPerson");
                          
                                    if (this.selectedPerson != null) {
                                         log.info(">>>>> get getSelectedPerson selectedPerson = "
                                                   + this.selectedPerson.getFirstName());
                                    }
                                    return this.selectedPerson;
                               }
                          
                               @Override
                               public void setSelectedPerson(Person person) {
                                    this.selectedPerson = person;
                               }
                          
                          
                               @Override
                               public void test() {
                                    System.out.println("test");
                                    System.out.println(selectedPerson == null ? "null" : selectedPerson.getEmail());
                               }
                          }
                          



                          The output when selecting a person in the selectOneMenu:


                          20:33:02,265 INFO  [PersonActionBean] >>>>> get selectedPerson
                          20:33:02,266 INFO  [PersonActionBean] >>>>> get getSelectedPerson selectedPerson = Jimmy
                          20:33:02,266 INFO  [PersonActionBean] >>>>> get selectedPerson
                          20:33:02,267 INFO  [PersonActionBean] >>>>> get getSelectedPerson selectedPerson = Jimmy
                          20:33:02,269 INFO  [STDOUT] test
                          20:33:02,269 INFO  [STDOUT] john@foo.bar
                          



                          The log above is when I changed from 'jimmy' to 'john'.

                          • 10. Re: Yet another problem with h:selectOneMenu value not changing
                            notify
                            (personList is a seam-gen generated ‘standard’ list for a Person entity



                            Not using Seam-Gen, can you elaborate or post seam-gen code.


                            Many thanks.

                            • 11. Re: Yet another problem with h:selectOneMenu value not changing
                              mrblacksmith

                              The getResultList() in




                              personsToTrack = personList.getResultList();
                              




                              is declared in org.jboss.seam.framework.EntityQuery you can have a look at it there if you want.


                              PersonList:



                              import org.jboss.seam.framework.EntityQuery;
                              
                              @Name("personList")
                              public class PersonList extends EntityQuery<Person> {
                              
                                   private static final String EJBQL = "select person from Person person";
                              
                                   private static final String[] RESTRICTIONS = {
                                             "lower(person.firstName) like lower(concat(#{personList.person.firstName},'%'))",
                                             "lower(person.lastName) like lower(concat(#{personList.person.lastName},'%'))",
                                             };
                              
                                   private Person person = new Person();
                              
                                   public PersonList() {
                                        setEjbql(EJBQL);
                                        setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
                                        setMaxResults(25);
                                   }
                              
                                   public Person getPerson() {
                                        return person;
                                   }
                              }
                              




                              Person:




                              @Entity
                              @Table(name = "person", catalog = "testdb")
                              public class Person implements java.io.Serializable {
                              
                                   private Long id;
                                   private Integer version;
                                   private String email;
                                   private String firstName;
                                   private String lastName;
                              
                                   public Person() {
                                   }
                              
                                   @Id
                                   @GeneratedValue(strategy = IDENTITY)
                                   @Column(name = "id", unique = true, nullable = false)
                                   public Long getId() {
                                        return this.id;
                                   }
                              
                                   public void setId(Long id) {
                                        this.id = id;
                                   }
                              
                                   @Version
                                   @Column(name = "version")
                                   public Integer getVersion() {
                                        return this.version;
                                   }
                              
                                   public void setVersion(Integer version) {
                                        this.version = version;
                                   }
                              
                                   @Column(name = "email", nullable = false, length = 20)
                                   @NotNull
                                   @Length(max = 20)
                                   @Email
                                   public String getEmail() {
                                        return this.email;
                                   }
                              
                                   public void setEmail(String email) {
                                        this.email = email;
                                   }
                              
                                   @Column(name = "firstName", nullable = false, length = 30)
                                   @NotNull
                                   @Length(max = 30)
                                   public String getFirstName() {
                                        return this.firstName;
                                   }
                              
                                   public void setFirstName(String firstName) {
                                        this.firstName = firstName;
                                   }
                              
                                   @Column(name = "lastName", nullable = false, length = 30)
                                   @NotNull
                                   @Length(max = 30)
                                   public String getLastName() {
                                        return this.lastName;
                                   }
                              
                                   public void setLastName(String lastName) {
                                        this.lastName = lastName;
                                   }
                              
                                   @Override
                                   public int hashCode() {
                              // removed to shorten post
                                   }
                              
                                   @Override
                                   public boolean equals(Object obj) {
                              // removed to shorten post
                                      }
                              }
                              





                              • 12. Re: Yet another problem with h:selectOneMenu value not changing
                                notify

                                I'm using the EJB3 Java Persistence API to create the list of DevicesToTrack, so the list returned is the same.


                                private List <DevicesToTrack> devicesToTrackList = new ArrayList <DevicesToTrack> ();
                                



                                @Factory("devicesToTrackList")  
                                public List <DevicesToTrack> getDevicesToTrack() {
                                    log.info(">>>>> getDevicesToTrack credentials = " + credentials.getUsername());
                                         
                                    final Query query = entityManager.createQuery(GET_DEVICES_TO_TRACK);
                                    query.setParameter(ONE, credentials.getUsername());
                                         
                                    this.devicesToTrackList = query.getResultList();
                                    log.info(">>>>> getDevicesToTrack devicesToTrackList size = " + this.devicesToTrackList.size());
                                          
                                    return this.devicesToTrackList;
                                }
                                



                                String GET_DEVICES_TO_TRACK = "SELECT d FROM DevicesToTrack d WHERE (d.devicesToTrackPK.emailAddress = ?) 
                                    ORDER BY d.vehicleAllocatedTo";
                                



                                I still get the first entry from the list no matter what I select from the drop down.


                                I can't see what I'm doing differently, except the way I retrieve the list for;


                                <s:selectItems value="#{devicesToTrackList}" var="devicesToTrack" label="#{devicesToTrack.vehicleAllocatedTo}" />
                                



                                The only thing I don't understand is the getPerson method in the class, is this key to getting the value selected from the dropdown?


                                My getSelectedDeviceToTrack is just a method in my EJB (Action);


                                @Override
                                public DevicesToTrack getSelectedDevicesToTrack() {
                                    if (this.selectedDevicesToTrack != null) {
                                     log.info("..... GET getSelectedDevicesToTrack selectedDevicesToTrack = " + this.selectedDevicesToTrack.getVehicleAllocatedTo());
                                    }
                                
                                    return this.selectedDevicesToTrack;
                                }
                                



                                Where as you have your getPerson method in;


                                @Name("personList")
                                public class PersonList extends EntityQuery<Person> {
                                
                                     private static final String EJBQL = "select person from Person person";
                                
                                     private static final String[] RESTRICTIONS = {
                                               "lower(person.firstName) like lower(concat(#{personList.person.firstName},'%'))",
                                               "lower(person.lastName) like lower(concat(#{personList.person.lastName},'%'))",
                                               };
                                
                                     private Person person = new Person();
                                
                                     public PersonList() {
                                          setEjbql(EJBQL);
                                          setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
                                          setMaxResults(25);
                                     }
                                
                                     public Person getPerson() {
                                          return person;
                                     }
                                }
                                



                                Thanks for your assistance but I'm well and truly stumped.

                                • 13. Re: Yet another problem with h:selectOneMenu value not changing
                                  mrblacksmith

                                  I understand you're frustrated...


                                  I don't use getPerson in PersonList in this example, I only use PersonList to get the resultList.


                                  I'm no expert, but I've seen references pointing to problems when not overriding hashcode/equals in the entity - have you implemented hashCode and equals in DevicesToTrack?


                                  I might have time later today to make some more test to try to reproduce your problem.

                                  • 14. Re: Yet another problem with h:selectOneMenu value not changing
                                    notify

                                    Marcus Smedman wrote on Nov 27, 2009 13:40:


                                    I'm no expert, but I've seen references pointing to problems when not overriding hashcode/equals in the entity - have you implemented hashCode and equals in DevicesToTrack?



                                    Yes, I've come across a number of postings re overriding hashcode/equals in the entity . I've overridden them with return set to 'true' to ensure it is equal. It did solve a earlier h:selectOneMenu problem, that used;


                                    <h:selectOneMenu value="#{selectedUserTitle}" id="title" required="true" >
                                        <s:selectItems value="#{userTitlesList}" 
                                         var="userTitles" 
                                         label="#{userTitles.title}" 
                                         noSelectionLabel="Please Select ..." />
                                        <s:convertEntity/> 
                                    </h:selectOneMenu> 
                                    



                                    and


                                     <h:commandButton id="save"
                                         value="Save"
                                         action="#{usersBean.addUser}"/>
                                    



                                    That worked and the title was passed to the EJB to persisted the user to a table.


                                    Thanks for all your efforts. Never had a problem taking up this amount of time in Java/J2EE/EE5, makes we regret going down the Seam route, as this stopping me deploying the website and app live!

                                    1 2 Previous Next