7 Replies Latest reply on Jun 20, 2012 2:43 PM by healeyb

    How to pass an argument to the backing-bean?

    grattler

      I am using RF4 and I want to call a method in my backing bean every time when the value of the inputText-field was changed.

       

      In the backing-bean I need two values from the client:

       

      a) The old value and the new entered value from the inputText-field.

      b) The current row from the data-table (called record).

       

      <rich:dataTable value="#{bean.list}" var="record">

      <rich:column>

          <h:inputText value="#{record.value}" size="7" rendered="#{record.copy}"

             valueChangeListener="#{bean.valueChanged}">

             <a4j:ajax event="change" execute="@this"

                  listener="#{bean.callListener}" render="richTab"/>

          </h:inputText>

      </rich:column>

      </rich:dataTable>

       

      To get the old value and the new entered value from the inputText-field, I use the valueChangeListener from inputText. In my backing-bean I save these values into instance-variables, because the valueChangeListener was invoked first and the listener was invoked after the valueChangeListener, but only the valueChangeListener is able to access the old value.

       

      After that, I want to calculate with both values within a listener-method, update the model and update the data-table to display the changes.

       

      My two-step-approach is cumbersome and looks error-prone, but I have not found another possibility than valueChangeListener to pass the old value to my backing-bean.

       

      In my listener-method callListener I need the current row from the data-table (called record).

       

      How can I pass the record-variable into the listener-method?

       

      Kind regards

      Oliver

        • 1. Re: How to pass an argument to the backing-bean?
          healeyb

          To get the data table row you need to use:

           

          <rich:dataTable ... var="record">

          ...

             <a4j:ajax .../>

             <f:setPropertyActionListener target="#{bean.currentRow}"

                                                       value="#{record}"/>

          </rich:dataTable>

           

          where the type of currentRow is the generic type of the rich:dataTable value= attribute. I don't see the need for

          both a valueChangeListener and an ajax listener. Why not just do the necessary logic in the valueChangeListener

          (which as you rightly point out has access to the new value) and have the a4j:ajax without the listener method.

          You don't need to "pass" the old value, it's already in the model by definition because you have a value= attribute

          in inputText.

           

          Just note that the default event for an input component is actually "valueChange", not "change", and sometimes

          "change" doesn't do quite what you want, but it's easily tested. I normally just use the default and not specify

          event=.

           

          Regards,

          Brendan.

          1 of 1 people found this helpful
          • 2. Re: How to pass an argument to the backing-bean?
            grattler

            Hi Brendan,

             

            thank you for the tips. I have changed the inputText-tag like followed:

             

            <rich:column>

                <h:inputText value="#{record.value}" size="7" rendered="#{record.copy}"

                   valueChangeListener="#{bean.valueChanged}">

                   <a4j:ajax event="valueChange" execute="@this"

                      listener="#{bean.callListener}" render="richTab" />

                   <f:setPropertyActionListener target="#{bean.selectedEntryToCopy}"

                      value="#{record}"/>

                </h:inputText>

            </rich:column>

             

            This does not work. The browser displays an error-message: Parent is not of type ActionSource.

            Is it wrong to nest the setPropertyActionListener within the inputText-tag?

             

            In my business logic I sometimes override the setter-value.

            Was the valueChangeListener invoked after the setter-method from inputText?

            <a4j:ajax execute="@this" render="richTab" /> will call the setter-method too, isn't it?

             

            After finishing my business logic method there should be no further setter-call with the new value.

            This was the reason for the ajax-listener to invoke the business logic.

             

            Kind regards

            Oliver

            • 3. Re: How to pass an argument to the backing-bean?
              healeyb

              Right, a silly mistake on my part. I've got to say that a) I always use a UICommand component in these situations

              so that I can use setPropertyActionListener, and b) I'm using extendedDataTable. There is an example from

              Practical Richfaces 2, which does this:

               

              <a4j:jsFunction name="updateDetails" render="???">

                  <a4j:param name="rowKey" assignTo="#{bean.currentRow}"/>

              </a4j:jsFunction>

              <rich:dataTable rowKeyVar="key" onrowclick="updateDetails(#{key})" ...

               

              currentRow will be an index, so if you have a List<Something> mylist, mylist.get(currentRow) should give you the

              row data.

               

              Note <a4j:param name="rowKey", it could be name="slartibartfast" and it would still work. The first a4j:param

              matches up with the first parameter to updateDetails which is #{key} etc...

               

              >Was the valueChangeListener invoked after the setter-method from inputText? NO


              Regards,

              Brendan.

              • 4. Re: How to pass an argument to the backing-bean?
                grattler

                Hi Brendan,

                 

                I have switched to extendedDataTable and I am using the <a4j:jsFunction>.

                Great approach. It's working, it's easy to understand and I can use the row-key in other methods, too!

                Very nice solution. I am excited!

                 

                Slartibartfast is a funny name for a param-name, but I prefer jigsaw.

                 

                Thank you for your help.

                 

                Kind regards

                Oliver

                • 5. Re: How to pass an argument to the backing-bean?
                  healeyb

                  Great, looks like things are moving in the right direction. With extendedDataTable you can do things a bit differently.

                  There's a bit of boilerplate code required in the selectionchange listener, and this version only works for

                  selectionMode="single". Assuming the extendedDataTable has a value= which is a List<MyGenericType> this will

                  get you the selected row in selectedSomething.

                   

                  <rich:extendedDataTable

                     selectionMode="single"

                     selection="#{bean.selectedRow}"

                      ...

                     <a4j:ajax render="???"

                                   event="selectionchange"

                                   listener="#{bean.mytableRowSelect}"/>

                     ...

                  </rich:extendedDataTable>

                   

                  class Bean ... {

                   

                     private Collection<Object> selectedRow;

                      private MyGenericType selectedSomething;

                   

                     public void memberRowSelect(AjaxBehaviorEvent event) {

                          UIExtendedDataTable dataTable = (UIExtendedDataTable) event.getComponent();

                          Object originalKey = dataTable.getRowKey();

                          Object selectionKey = selectedMember.toArray()[0];

                          dataTable.setRowKey(selectionKey);

                          if (!dataTable.isRowAvailable()) {

                              return;

                          }

                   

                          MyGenericType selectedSomething = (MyGenericType) dataTable.getRowData();

                   

                          dataTable.setRowKey(originalKey);

                      }

                   

                     // getters & setters required

                     }

                   

                  Regards,

                  Brendan.

                  1 of 1 people found this helpful
                  • 6. Re: How to pass an argument to the backing-bean?
                    grattler

                    Hi Brendan,

                     

                    thank you for the selectionchange listener.

                     

                    I have implemented it and it works, but the difficulty lies in the detail.

                     

                    One column of my data-table contains a delete-button.

                     

                    When I delete row 5 (for example), the selectionchange listener was called and my bean was notified with the fifth object.

                    After that, this object was deleted from my model and the data-table was rendered.

                    Then I want to delete the fifth row again (which was the sixth row before deleting and rendering occurs).

                    The selected line was the same as before, and the data-table doesn't fire a selectionchange listener, even though the data-table was rerendered.

                    The second row-deletion will not work, because the bean contains the wrong selected row.

                    The bean contains still the stale row that was deleted in the first place.

                     

                    Without deleting & rerendering  the selectionchange listener would work.

                    But in my case I must use the <a4j:jsFunction> and the row-key.

                     

                    Kind regards

                    Oliver

                    • 7. Re: How to pass an argument to the backing-bean?
                      healeyb

                      Whenever you make any changes to the underlying data you have to ensure that:

                       

                      a) the model (i.e. what is referenced by the rich:dataTable value= attribute) is refreshed, and

                       

                      b) the actual table (the rich:dataTable id=) is refreshed by any ajax render= component that

                      is making changes to the underlying data.

                       

                      You shouldn't be accessing the database in getters so hopefully you have another way of

                      doing this.

                       

                      Regards,

                      Brendan.