9 Replies Latest reply on Apr 16, 2010 5:46 AM by nbelaevski

    Datatable and APPLY_REQUEST_VALUES

    samkwitty

      I am using 3.3.2.sr1 and it appears that datatable calls the backend bean during the APPLY_REQUEST_VALUES when it is constructing its data model. This is a bit of an issues since the backend bean may rely on other backend beans which don't get called until the UPDATE_MODEL phase.

       

      If my understanding is correct then this is a bug since backend beans should not be called until UPDATE_MODEL according to the JSF spec.

       

      Is there a workaround for this?

        • 1. Re: Datatable and APPLY_REQUEST_VALUES
          nbelaevski

          Hi Sam,

           

          No, this is not a bug. Methods of backing beans can be called on each phase, since the very first one. You should remodel your beans so that they won't be dependent on the current phase.

          • 2. Re: Datatable and APPLY_REQUEST_VALUES
            samkwitty

            Hi Nick,

             

            Thanks for the quick response... However I am not depending on the phase... Here is a simple example.

             

            Say you have a page that displays information about a user in a datatable. At the top of that page you have a drop down that change what user the information is displayed for.

             

            Say your bean looks something like this:

             

            class UserInfo

            {

              getCurrentUser()

              setCurrentUser()

             

              getUserData()

            }

             

            When you change the combobox getUserData is called first during the APPLY_REQUEST_VALUES before setCurrentUser is called in response to a change in the dropdown. This is because it is part of the datatable display. So now getUserData is returning the wrong data for the selected user. Now it does get called again later on during the UPDATE_MODEL_VALUES phase (after setCurrentUser is called) but if you are caching your results (say request scope bean) then you are getting stale data. You can reload it again but if this is a db request that is really expensive.

             

            What am I missing?

            • 3. Re: Datatable and APPLY_REQUEST_VALUES
              nbelaevski

              In JSF iteration components reset their models before rendering (that's true for the case when no errors happened during request processing).

              So, data should be requested two times: on the 2nd-4th phases submitted data is processed (and that's the reason for the data table to request data from the bean), on 5th phase actions are taking place, but on 6th phase data should be re-fetched.

               

              I'm not sure I fully understand your case, but you can try doing assignment of currentUser in action and reset cached data there.

               

              BTW, consider common input component. If it has its value changed, it fires ValueChangeEvent, evaluating bean property in order to get previous value. And this can happen on the 3rd or on the 2nd phases. 

               

              Message was edited by: Nick Belaevski

              • 4. Re: Datatable and APPLY_REQUEST_VALUES
                samkwitty

                Nick,

                 

                Perhaps I over simplified. Let me use a slightly more complex example.

                 

                In the header of the page I have a combobox. This one is global it shows up on ever page therefore it sets a session wide variable called currentUser in some session bean. Changing the combox value changes the global session variable and cause the page to re-render with the values for the selected user.

                 

                <h:form>
                  <h:selectOneMenu value="#{jsfUtils.currentUserUIDString}" onchange="submit()">
                    <c:forEach var="member" items="#{accountManager.sortedMembers}">
                      <f:selectItem itemLabel="#{member.profile.fullName}" itemValue="#{member.id}"/>
                    </c:forEach>
                  </h:selectOneMenu>
                <h:form>

                 

                 

                On one of the pages I have a table that displays user info through the userInfoBackend bean which has request scope.

                <rich:dataTable value="#{userInfoBackend.data}" var="data">

                  <rich:columns value="#{userInfoBackend.columnNames}" var="columns" index="columnIndex">
                    <f:facet name="header">#{columns}</f:facet>
                    <h:outputText value="#{data[columnIndex]}"/>
                  </rich:columns>
                </rich:dataTable> 

                 

                The data for user info comes from the db. So on first call to userInfoBackend.data I cache the db data. However, that gets called before   jsfUtils.currentUserUIDString is called in response to a change in the combobox which means I am grabbing data for the wrong person. I can forgo the caching which means I would ask for the data twice. The first time for the wrong user and the second time for the right user.

                 

                Resetting the data in the cache through the action event is not really feasible since there N possible request beans (one for every page in the applicaton) that data would have to be reset in. And even if I could do that it would still force a double DB hit.

                 

                My current workaround is to have the following code at the top of every page that essentially lets the backend bean know that it is ok to go to the db and grab data. But it is super ugly. There must be a better way.

                 

                <h:panelGroup layout="block" style="widht:0px; height=0px; position:absolute;">

                  ${userInfoBackend.okToDo}

                </h:panelGroup> 

                 

                Thanks for the help

                -Sam

                • 5. Re: Datatable and APPLY_REQUEST_VALUES
                  nbelaevski

                  Once again: double db hit is necessary if you have components that are really being processed on execute part of lifecycle. If that's not so, you have plenty of workarounds possible:

                   

                  - make the whole table transient

                  - return fake model for the execute part of lifecycle (coordinate this via phase listener)

                  - make table non-rendered for the execute part of lifecycle

                  - use a4j:region to limit processing

                   

                  One more can be usage of SerializableDataModel.

                  1 of 1 people found this helpful
                  • 6. Re: Datatable and APPLY_REQUEST_VALUES
                    samkwitty

                    Nick,

                     

                    Not sure what you mean by "make the table transient" (this might be my lack of knowledge).

                     

                    I did change my workaround to use an ajax submit with an ajaxSingle="true" essentially the same thing as your region suggestion and then force a refresh of the rest of the page. It esently forces a processing order causing the comobox to be processed first and table second.

                     

                    <a4j:form ajaxSubmit="true" ajaxSingle="true" reRender="rest of page">
                      <h:selectOneMenu value="#{userInfo.currentUser}"

                                       immediate="true"

                                       valueChangeListener="#{userInfo.setCurrentUserListener}"

                                       onchange="submit()">
                        <c:forEach var="member" items="#{accountManager.sortedMembers}">
                          <f:selectItem itemLabel="#{member.profile.fullName}" itemValue="#{member.id}"/>
                        </c:forEach>
                      </h:selectOneMenu>
                    </a4j:form>

                    • 7. Re: Datatable and APPLY_REQUEST_VALUES
                      nbelaevski

                      Not sure what you mean by "make the table transient" (this might be my lack of knowledge).

                      Just add attribute: transient="true".

                      • 8. Re: Datatable and APPLY_REQUEST_VALUES
                        samkwitty

                        Nick,

                         

                        Thanks... is that documented somewhere? I looked here: http://docs.jboss.org/richfaces/latest_3_3_X/en/tlddoc/rich/dataTable.html but no mention of transient.

                        • 9. Re: Datatable and APPLY_REQUEST_VALUES
                          nbelaevski

                          It's part of StateHolder interface, check Javadoc for javax.faces.component.StateHolder.isTransient().