6 Replies Latest reply on Mar 15, 2007 6:03 PM by tazman

    a4j:commandButton doesn't submit form field whereas a4j:supp

    tazman

      Hi all!

      I'm having a difficult time with a form for user registration. I'm using a4j 1.0.7 with Seam 1.2 on top of JBoss 4.0.5.

      The form looks like this:

      <h:form id="register_form">
      <!-- OTHER FORM FIELDS LIKE name, username, etc.-->
      
      <a:region id="locationRegion" selfRendered="false" renderRegionOnly="false">
      
       <!-- country -->
       <h:outputLabel for="country">country</h:outputLabel>
       <h:selectOneMenu id="country" value="#{location.country}" required="false">
       <f:selectItems value="#{location.countries}"/>
       <a:support event="onchange" reRender="statePanel, cityPanel" limitToList="true" ajaxSingle="true"/>
       </h:selectOneMenu>
      
       <!-- state -->
       <h:outputLabel for="state">state</h:outputLabel>
       <a:outputPanel id="statePanel">
       <h:selectOneMenu id="state" value="#{location.state}" required="false">
       <f:selectItems value="#{location.states}"/>
       <a:support event="onchange" reRender="cityPanel" limitToList="true"/>
       </h:selectOneMenu>
       </a:outputPanel>
      
       <!-- city -->
       <h:outputLabel for="city">city</h:outputLabel>
       <a:outputPanel id="cityPanel">
       <h:selectOneMenu id="city" value="#{location.city}" required="false">
       <f:selectItems value="#{location.cities}"/>
       </h:selectOneMenu>
       </a:outputPanel>
      </a:region>
      
      <a:commandButton reRender="register_form" value="submit" action="#{userManager.persist}"/>
      </h:form>


      location.countries generates a static list of countries. location.states and location.cities loads the list from DB depending on the selected country and state.

      // SOME DETAILS ARE OMITTED
      public class Location {
       private String country;
       private String state;
       private String city;
      
       public Map<String, String> getCountries() {
       // returns a static Map for use in select options
       }
      
       public Map<String, String> getStates() {
       //loads the list of states from DB
       }
      
       public Map<String, String> getCities() {
       //loads the list of cities from DB
       }
       ...
      }


      Now, when I change the country from the selection list, onchange event is fired, new lists of states and cities are loaded from the database and rerendering occurs correctly. However, if I click on the submit button, the selected values for the country and state are null.

      I tried to debug the application. Using a4j log in the browser I can see that in both cases, a:support and a:commandButton, the values are submitted. But in the second case, location.getStates() and location.getCities() get null values for country and state when JSF tries to rebuild the states and cities lists after form submit.

      I don't know why this happens. Any ideas?

      P.S.: I'm using a region inside the form so that when state changes, country value is also submitted. Otherwise the fields outside of the region get also submitted, which causes validation errors.

      tazman


        • 1. Re: a4j:commandButton doesn't submit form field whereas a4j:

          When you click the button, does the query string contain the values for location drop down boxes?

          What is the scope for #{location} ?

          • 2. Re: a4j:commandButton doesn't submit form field whereas a4j:
            tazman

            Hi Sergey!

            Thanks for your reply. I was experimenting with different scopes for location. Currently it is SESSION, but I got the same results with EVENT and PAGE scopes as well.

            I tried to output some debug messages with some JSF phase info. If I select US as country and then california as state, I see this in the logs:

            18:40:50,833 DEBUG [JSFLifeCycleListener] BeforePhase: RESTORE_VIEW 1
            18:40:50,923 DEBUG [JSFLifeCycleListener] AfterPhase: RESTORE_VIEW 1
            18:40:50,933 DEBUG [JSFLifeCycleListener] BeforePhase: APPLY_REQUEST_VALUES 2
            18:40:50,933 DEBUG [JSFLifeCycleListener] AfterPhase: APPLY_REQUEST_VALUES 2
            18:40:50,943 DEBUG [JSFLifeCycleListener] BeforePhase: PROCESS_VALIDATIONS 3
            18:40:50,963 INFO [STDOUT] Location -- getStates for country: us
            18:40:50,973 DEBUG [JSFLifeCycleListener] AfterPhase: PROCESS_VALIDATIONS 3
            18:40:50,973 DEBUG [JSFLifeCycleListener] BeforePhase: UPDATE_MODEL_VALUES 4
            18:40:50,973 INFO [STDOUT] Location -- country set to: us
            18:40:50,983 INFO [STDOUT] Location -- state set to: california
            18:40:50,983 INFO [STDOUT] Location -- city set to: null
            18:40:50,983 DEBUG [JSFLifeCycleListener] AfterPhase: UPDATE_MODEL_VALUES 4
            18:40:50,983 DEBUG [JSFLifeCycleListener] BeforePhase: INVOKE_APPLICATION 5
            18:40:50,983 DEBUG [JSFLifeCycleListener] AfterPhase: INVOKE_APPLICATION 5
            18:40:51,003 DEBUG [JSFLifeCycleListener] BeforePhase: RENDER_RESPONSE 6
            18:40:51,193 INFO [STDOUT] Location -- getCities for country and state: us california
            18:40:51,604 DEBUG [JSFLifeCycleListener] AfterPhase: RENDER_RESPONSE 6


            After that the cities/places for california are loaded. I select one of them, fill in other fields like name, username, etc. and click on submit. Now the log is a lot different:

            18:40:50,848 DEBUG [JSFLifeCycleListener] BeforePhase: RESTORE_VIEW 1
            18:43:50,898 DEBUG [JSFLifeCycleListener] AfterPhase: RESTORE_VIEW 1
            18:43:50,898DEBUG [JSFLifeCycleListener] BeforePhase: APPLY_REQUEST_VALUES 2
            18:43:50,898DEBUG [JSFLifeCycleListener] AfterPhase: APPLY_REQUEST_VALUES 2
            18:43:50,898DEBUG [JSFLifeCycleListener] BeforePhase: PROCESS_VALIDATIONS 3
            18:43:50,898INFO [STDOUT] Location -- getStates for country: null
            


            At this point rebuilding the states list fails and I get a java.util.NoSuchElementException.

            So when a:commandButton is activated, the country is null in the PROCESS_VALIDATIONS phase (even though location is SESSION scoped), whereas it is set to the selected country when a:support fires an onchange event. I don't know why this could happen.

            BTW, when I click the button the query string contains all the values in the form.

            I would appreciate any help. Thanks

            tazman


            • 3. Re: a4j:commandButton doesn't submit form field whereas a4j:

              How the #{location} bean java code looks like?

              Also, try the following changes:
              1. remove the a4j:region
              2. Add ajaxSingle="true" to a4j:support for your drop down boxes

              • 4. Re: a4j:commandButton doesn't submit form field whereas a4j:
                tazman

                Hi Sergey!

                Thank you for your suggestions. Before I saw your reply I succeeded to solve the issue in a way, which is somehow the opposite what you suggested.

                I took a deep look into the logs and found out that, whenever a:support fired an event for a field outside of the location region, like this one for email address:

                <a:support event="onblur" reRender="emailErrors" limitToList="true" ajaxSingle="true"/>


                all other fields, including the fields in my location object, was getting null values. These null values were overwriting my previous country and state selections. That's why these fields were null when I clicked on the submit button. During my tests, I was first selecting the country/state/city and then filling in other fields, which were firing onblur events and overwriting my previous selections. It would probably work if I would change this order.

                Nevertheless, this is something that I didn't expect to happen with ajaxSingle="true". I thougt that, when the event is fired for email, only the setEmail() method in my object would get called with the new value, and nothing more. However, other setter methods in the location object are called as well.

                The solution I implemented was to define an additional region for the other form fields. I have now two regions in my form and an onblur event for email does set all the fields (but email) in that region to null. But beacuse my location object is in another region, they remain untouched by these events.

                tazman

                • 5. Re: a4j:commandButton doesn't submit form field whereas a4j:

                  Do you use MyFaces or JSF-RI, by the way?

                  • 6. Re: a4j:commandButton doesn't submit form field whereas a4j:
                    tazman

                    I'm using JSF-RI 1.2 with Facelets.

                    tazman