14 Replies Latest reply on Oct 10, 2005 10:46 AM by lcoetzee

    selectManyCheckbox set problem

    lcoetzee

      Hi all,

      this I assume is a pure JSF problem using Seam as the glue, but maybe someone has solved this.

      I have a selectManyCheckbox as follows:

      <h:selectManyCheckbox value="#{portalUserManagement.selectedPortalRoles}"
      rendered="#{allPortalRoles != null and not empty allPortalRoles}"
      layout="pageDirection" id="fubar">
      <f:selectItems
      value="#{portalUserManagement.allPortalRolesAsSelects}" />
      </h:selectManyCheckbox>


      In my ActionHandler I have the appropriate set/get for both allPortalRolesAsSelects and selectedPortalRoles (as well as being defined in my Local Interface) :

      @Out(required = false)
      private List<SelectItem> allPortalRolesAsSelects;
      @In(required = false)
      @Out(required = false)
      private String[] selectedPortalRoles;
      


      allPortalRolesAsSelects gets populated with normal ItemSelect's containing Strings while selectedPortalRoles are set to the initial selected values (Strings).

      On display the view is rendered correctly (with the correct checkboxes ticked based on the initial values). I can see that my getSelectedPortalRoles is called. Unfortunately on submit the setSelectedPortalRoles is never being called resulting in my bean not getting the values.

      I am using facelets 0.9.8 and have tried it with both MyFaces 1.0.9 and 1.1.0.

      Any suggestions ?

      Thanks

      Louis


        • 1. Re: selectManyCheckbox set problem

          can you post the XML/java snippets for your page?

          i will have to check the myfaces code, but what may be happening is that the rendered attribute is being evaluated as a predicate to decoding the form post-- returning false because Seam hasn't scoped those properties for evaluation in EL.

          Again, I would not use @Out and see if that corrects the problem.

          -- Jacob

          • 2. Re: selectManyCheckbox set problem
            lcoetzee

            Hi Jacob,

            I built a Stateful bean with associated xhtml. Below is how I think it should be. The initial selections are being set on the view page. Unfortunately on Submit the new selections are not being transferred to my bean. (I have tried all sort of combinations not using @Out and not declaring the accessor methods in my @Local interface, but this is the closest I have come to get it almost working).

            My interface for the bean

            
            @Local
            public interface SelectLots {
            
             public String seedSelection();
            
             public String submitSelection();
            
             public String cancelSelection();
            
             public List<SelectItem> getChoices();
            
             public String[] getSelectedChoices();
            
             public void setSelectedChoices(String[] selected);
            
            }
            


            The implementation of the stateful bean:
            @Stateful
            @Name("selectMany")
            @Interceptor(SeamInterceptor.class)
            public class SelectLotsAction implements SelectLots, Serializable {
            
             static final Logger logger = Logger.getLogger(SelectLotsAction.class);
            
             @In(required = false)
             @Out(required = false)
             String[] selectedChoices;
            
             @Out(required = false)
             List<SelectItem> choices;
            
             private static final long serialVersionUID = -2760798987306066205L;
            
             public SelectLotsAction() {
             }
            
             private void populate() {
             logger.info("Populated with defaults");
             choices = new ArrayList<SelectItem>();
             // seed with choices
             choices.add(new SelectItem("One"));
             choices.add(new SelectItem("Two"));
             choices.add(new SelectItem("Three"));
             choices.add(new SelectItem("Four"));
            
             // our intial selections
             selectedChoices = new String[2];
             selectedChoices[0] = "One";
             selectedChoices[1] = "Four";
             }
            
             @Begin
             public String seedSelection() {
             populate();
             return "populated";
             }
            
             @End
             public String submitSelection() {
             logger.info("What happened to the selections?");
             if (selectedChoices != null) {
             for (int i = 0; i < selectedChoices.length; i++) {
             logger.info("New selection: " + selectedChoices);
             }
             } else {
             logger.info("Selections are null ! Not suppose to be");
             }
             return "success";
             }
            
             @End
             public String cancelSelection() {
             return "cancel";
             }
            
             public List<SelectItem> getChoices() {
             logger.info("Retrieving all possible selections");
             return choices;
             }
            
             public String[] getSelectedChoices() {
             logger.info("Retrieving the default selections");
             return selectedChoices;
             }
            
             public void setSelectedChoices(String[] selected) {
             logger.info("Setting the new selections");
             this.selectedChoices = selected;
             }
            
             }
            

            and finally a snippet of my xhtml

            
             <ui:define name="body">
             <h:messages />
             <h:form>
             <h:panelGrid id="roles_grid" columns="1">
             <h:commandButton id="getroles_button"
             value="Retrieve and manage selection"
             action="#{selectMany.seedSelection}" rendered="#{choices == null}" />
             <h:selectManyCheckbox value="#{selectedChoices}"
             rendered="#{choices != null and not empty choices}" layout="pageDirection"
             id="fubar" required="true">
             <f:selectItems value="#{choices}" />
             </h:selectManyCheckbox>
             <h:commandButton id="submit_button" value="Save"
             action="#{selectMany.submitSelection}" />
             <h:commandButton id="cancel_button" value="Cancel" immediate="true"
             action="#{selectMany.cancelSelection}" />
             </h:panelGrid>
             </h:form>
             </ui:define>
            


            As mentioned in other threads I have managed to get the selectOneMenu going, but this one has me bowled.

            Thanks

            Louis

            • 3. Re: selectManyCheckbox set problem
              gavin.king

              What happens if you use @Intercept(ALWAYS)?

              • 4. Re: selectManyCheckbox set problem
                lcoetzee

                Nope, no difference. Still not getting the selections back to my Seam bean.

                As an aside, I have upgraded all I could to the latest versions I could get my hands on (CVS Head for Seam, jboss 4.0.3, MyFaces 1.1.0 and Facelets 1.0alpha).

                L

                • 5. Re: selectManyCheckbox set problem
                  xiangya

                  Hi,
                  May be you want check out that tag's id attribute:)

                  Regards.

                  xiangya

                  • 6. Re: selectManyCheckbox set problem
                    lcoetzee

                    Oops ;-) Late night madness !

                    • 7. Re: selectManyCheckbox set problem
                      gavin.king

                      so it works now?

                      • 8. Re: selectManyCheckbox set problem
                        lcoetzee

                        No unfortunately not. The id was an acronym for something that is broken (used in some or other movie where a lot of things got blown up).

                        I have simplified the xhtml by removing the rendered attribute from the selectMany. Unfortunately it didn;t make a difference.

                        The current xhtml snippet is the following:


                        <h:panelGrid id="select_grid" columns="1" rendered="#{choices != null and not empty choices}">
                         <h:selectManyCheckbox value="#{selectedChoices}"
                         layout="pageDirection" id="oops" required="true">
                         <f:selectItems value="#{choices}" />
                         </h:selectManyCheckbox>
                        </h:panelGrid>
                        


                        Very interesting actually.

                        Louis

                        • 9. Re: selectManyCheckbox set problem
                          gavin.king

                          ok, but you do not believe that seam is the source of the problem, right?

                          • 10. Re: selectManyCheckbox set problem
                            lcoetzee

                            I have been trying a few different things to possibly identify the source of my problem. One of those things was to cut and paste my code into a normal JSF application running with a normal backing bean on JBoss. In that environment it works as expected.

                            For me the problem can be at a few different layers:
                            1. Just me doing something stupid (and not understanding Seam well enough as yet).
                            2. The interaction between Facelets and JSF breaking something before it gets sent to backend.
                            3. Or seam breaking something when it receives it from the Facelets/JSF layer.

                            The concerning things for me is that I can clearly see the getter/setter methods being called in the standard JSF/backing bean application. In the Seam version of the code I never see those methods being called (I have log statements in the get/set stuff). Even though the defaults are being instantiated. How does the EL stuff get hold of values then ?

                            I am still trying different things/ways (e.g. I have created a seam entity where the values are set by the xhtml). This not working either. But I will continue to dig !

                            The only place where I have managed to get this kind of thing working was with a Converter (see a previous thread).

                            Later

                            L

                            • 11. Re: selectManyCheckbox set problem
                              lcoetzee

                              hi Gavin,

                              OK... I am a dumb ass (officially) !!!!!!! Turns out to be issue number one (me doing something stupid and not understanding Seam well enough) !!!!!

                              I will post the complete solution shortly !

                              Louis

                              • 12. Re: selectManyCheckbox set problem

                                I have the same problem now :-)
                                lcoetzee post complete solution please!!!

                                --Andrew

                                • 13. Re: selectManyCheckbox set problem
                                  lcoetzee

                                  Andrew... just shoot me ! I tried cleaning up my code and in the process I removed something that stopped it from working ! Even worse I can't figure out what it was. I am trying to get it back to what it was but no luck thus far !

                                  Frustration !

                                  Louis

                                  • 14. Re: selectManyCheckbox set problem
                                    lcoetzee

                                    Got it. The most important part is not to use bijection on the attributes you want to access from the view, but rather declare getter/setter methods in your interface. Below is my view, interface and implementation.

                                    Hope it helps

                                    Louis


                                    
                                    <ui:define name="body">
                                     <h:messages />
                                     <h:form id="selectionForm">
                                    
                                     <h:panelGrid id="roles_grid" columns="1">
                                    
                                     <h:commandButton id="getroles_button"
                                     rendered="#{selectMany.alreadyPopulated == null}"
                                     value="Retrieve and manage selection"
                                     action="#{selectMany.seedSelection}" />
                                    
                                    
                                     <h:panelGrid id="select_grid" columns="1"
                                     rendered="#{selectMany.alreadyPopulated != null}">
                                     <h:selectManyCheckbox value="#{selectMany.selectedChoices}"
                                     layout="pageDirection" id="oops" required="true">
                                     <f:selectItems value="#{selectMany.choices}" />
                                     </h:selectManyCheckbox>
                                     </h:panelGrid>
                                    
                                    
                                     <h:panelGrid id="select_one" columns="1"
                                     rendered="#{selectMany.alreadyPopulated != null}">
                                     <h:selectOneMenu value="#{selectMany.selectedSingleChoice}"
                                     id="oopsSingular" required="true">
                                     <f:selectItems value="#{selectMany.choices}" />
                                     </h:selectOneMenu>
                                     </h:panelGrid>
                                    
                                    
                                    
                                     <h:commandButton id="submit_button" value="Save"
                                     action="#{selectMany.submitSelection}" />
                                    
                                    
                                     <h:commandButton id="cancel_button" value="Cancel" immediate="true"
                                     action="#{selectMany.cancelSelection}" />
                                    
                                     </h:panelGrid>
                                    
                                     </h:form>
                                     </ui:define>
                                    
                                    
                                    


                                    My interface:
                                    package csir.learn.seam;
                                    
                                    import java.util.List;
                                    
                                    import javax.ejb.Local;
                                    import javax.faces.model.SelectItem;
                                    
                                    @Local
                                    public interface SelectLots {
                                    
                                     public String startMeOff();
                                    
                                     public String seedSelection();
                                    
                                     public String submitSelection();
                                    
                                     public String cancelSelection();
                                    
                                     public void endMeOff();
                                    
                                     public List<SelectItem> getChoices();
                                    
                                     public String[] getSelectedChoices();
                                    
                                     public void setSelectedChoices(String[] selected);
                                    
                                     public String getSelectedSingleChoice() ;
                                    
                                     public void setSelectedSingleChoice(String selectedSingleChoice) ;
                                    
                                     public String getAlreadyPopulated() ;
                                    
                                     public void setAlreadyPopulated(String alreadyPopulated);
                                    }
                                    
                                    

                                    And finally the implementation
                                    package csir.learn.seam;
                                    
                                    import java.io.Serializable;
                                    import java.util.ArrayList;
                                    import java.util.List;
                                    
                                    import javax.ejb.Interceptor;
                                    import javax.ejb.Remove;
                                    import javax.ejb.Stateful;
                                    import javax.faces.model.SelectItem;
                                    
                                    import org.apache.log4j.Logger;
                                    import org.jboss.seam.InterceptionType;
                                    import org.jboss.seam.annotations.Begin;
                                    import org.jboss.seam.annotations.Create;
                                    import org.jboss.seam.annotations.Destroy;
                                    import org.jboss.seam.annotations.End;
                                    import org.jboss.seam.annotations.Intercept;
                                    import org.jboss.seam.annotations.Name;
                                    import org.jboss.seam.ejb.SeamInterceptor;
                                    
                                    @Stateful
                                    @Name("selectMany")
                                    @Intercept(InterceptionType.ALWAYS)
                                    @Interceptor(SeamInterceptor.class)
                                    public class SelectLotsAction implements SelectLots, Serializable {
                                    
                                     static final Logger logger = Logger.getLogger(SelectLotsAction.class);
                                    
                                     /*
                                     * use this to decide when to show the commandButton, selectManyCheckbox, selectOneMenu
                                     */
                                     String alreadyPopulated;
                                    
                                     /*
                                     * Contains the results of the choices the user made on the selectManyCheckbox
                                     * Gets seeded with default values in @see populate() (One and Four)
                                     */
                                     String[] selectedChoices;
                                    
                                    
                                     /*
                                     * Contains the result of the choice the user made on the select selectOneMenu
                                     * Gets seeded with a default value in @see populate() (Three)
                                     */
                                     String selectedSingleChoice;
                                    
                                     /*
                                     * The initial items available for the user to select from (One, Two, Three, Four)
                                     */
                                     List<SelectItem> choices;
                                    
                                     private static final long serialVersionUID = -2760798987306066205L;
                                    
                                     public SelectLotsAction() {
                                     }
                                    
                                     @Create
                                     public String startMeOff() {
                                     logger.info("This is the start");
                                     return "notpopulated";
                                     }
                                    
                                     /**
                                     * Seed the initial choices as well as those items user can select from
                                     */
                                     private void populate() {
                                     choices = new ArrayList<SelectItem>();
                                     // seed with choices
                                     choices.add(new SelectItem("One", "One Label"));
                                     choices.add(new SelectItem("Two", "Two Label"));
                                     choices.add(new SelectItem("Three", "Three Label"));
                                     choices.add(new SelectItem("Four", "Four Label"));
                                    
                                     // our intial selections
                                     selectedChoices = new String[4];
                                     selectedChoices[0] = "One";
                                     selectedChoices[1] = "Four";
                                    
                                     // and the initial selection for a single select
                                     selectedSingleChoice = "Three";
                                    
                                     alreadyPopulated = new String("a value indicating we are populated");
                                     logger.info("Populated with defaults");
                                    
                                     }
                                    
                                     /**
                                     * Populate the initial choices. Start of our conversation
                                     */
                                     @Begin
                                     public String seedSelection() {
                                     populate();
                                     return "populated";
                                     }
                                    
                                     /**
                                     * See what the user submitted. End of our conversation
                                     */
                                     @End
                                     public String submitSelection() {
                                     logger.info("What happened to the selections?");
                                    
                                     if (selectedChoices != null) {
                                     for (int i = 0; i < selectedChoices.length; i++) {
                                     logger.info("New selection: " + selectedChoices);
                                     }
                                     } else {
                                     logger.info("Selections are null ! Not suppose to be");
                                     }
                                    
                                     logger.info("Single selection result");
                                     if (selectedSingleChoice != null) {
                                     logger.info("Single select returned : " + selectedSingleChoice);
                                     } else {
                                     logger.info("Single selection is null! Not suppose to be either");
                                     }
                                    
                                     return "success";
                                     }
                                    
                                     /**
                                     * User did not want to do anything. End of conversation
                                     */
                                     @End
                                     public String cancelSelection() {
                                     return "cancel";
                                     }
                                    
                                     @Destroy
                                     @Remove
                                     public void endMeOff() {
                                     logger.info("This is the end");
                                     }
                                    
                                     /**
                                     * getter and setter methods required by JSF/Facelets to populate view and retrieve selections
                                     */
                                     public List<SelectItem> getChoices() {
                                     logger.info("Retrieving all possible selections");
                                     return choices;
                                     }
                                    
                                     public String[] getSelectedChoices() {
                                     logger.info("Retrieving the default selections, String[]");
                                     return selectedChoices;
                                     }
                                    
                                     public void setSelectedChoices(String[] selected) {
                                     logger.info("Setting the new selections, String[]");
                                     this.selectedChoices = selected;
                                     }
                                    
                                     public String getSelectedSingleChoice() {
                                     logger.info("Retrieving the default single selection, String");
                                     return selectedSingleChoice;
                                     }
                                    
                                     public void setSelectedSingleChoice(String selectedSingleChoice) {
                                     logger.info("Setting the new single selection, String");
                                     this.selectedSingleChoice = selectedSingleChoice;
                                     }
                                    
                                     public String getAlreadyPopulated() {
                                     return alreadyPopulated;
                                     }
                                    
                                     public void setAlreadyPopulated(String alreadyPopulated) {
                                     this.alreadyPopulated = alreadyPopulated;
                                     }
                                     }