1 2 Previous Next 27 Replies Latest reply on Jul 1, 2010 1:38 PM by Dan Allen

    RichFaces 4.0: Controlling AJAX updates for iteration compon

    Nick Belaevski Master

      RichFaces contains several iteration components: sequential components (rich:dataTable, a4j:repeat, etc.) and hierarchical (rich:tree). For both of these families, it is important for the developer to have an ability to limit AJAX updates to certain row/tree node.
      Currently in 3.3.x this problem is solved by "ajaxKeys" attribute that points to a set of row keys for which to do updates. Here is an example of this:

      <rich:dataTable id="table" value="#{collection}" var="item" ajaxKeys="#{bean.ajaxKeys}">
       <rich:column>
       <h:panelGroup id="group">
       #{item.name}
       </h:panelGroup>
       </rich:column>
      </rich:dataTable>
      
      <a4j:commandLink value="Update" reRender="group" />


      public class Bean {
       //...
       public Object getAjaxKeys() {
       Set keys = new HashSet();
       keys.add(1);
       return keys;
       }
       //...
      }


      Updates are controlled by two distinct components: data table defines which rows to update (using "ajaxKeys") and command link defines IDs of the components to update.
      What is also sufficient is that output components with ajaxRendered="true" are also updated according to AJAX keys.
      If AJAX keys are not defined, then set with a single implicit key (it is the key of the row in which AJAX event happened for this request) is used. If no implicit key for this table exists, then the whole value collection is being iterated (causing highly-voted JIRA issue: https://jira.jboss.org/jira/browse/RF-3341).
      Also AJAX keys bound to session-scoped beans and not cleared after view is rendered can cause performance penalties due to excess updates.

      The main problem of ajax keys approach IMHO is that control on AJAX updates is separated between two different view components. Considering the fact that we are going to let all components consisting of several tags be constructed using nested a4j:repeat, I believe that necessity of nested ajaxKeys for these cases should be simplified radically.
      I think that another use-case that this approach doesn't cover is of very low importance and we can safely ignore it. That is the case of controlling updates for particular row components in a more agile manner, e.g. to update component "a" for rows 1, 3, 5 and component "b" for rows 1, 2, 3.

      To solve this problem, the following form of notation is proposed:
      render="form:table[12]:group" ...
      For me it seems to be a declarative and close to developer. However I see some problems with this approach:
      - Ranges/sets of rows are hard to address, possible solution:
      render="form:table[12, 13]:group"

      - Complex keys (e.g. hierarchical) doesn't fit well in this scheme, because developer currently need to convert them to string manually using some sort of converter that guarantees safe bidirectional object-string conversion

      Question for the case if we leave "ajaxKeys": do we need to add extra set of AJAX keys for auto-updated elements, e.g. messages updateable only in the processed rows?

      General problems of updates by key - usage of data items as update keys can be a possible solution:
      - Developer needs to know row keys, so this requires knowledge of how model creates them
      - Defines only replacement/updates, not insertion/deletion. Also for standard sequential models (e.g. list-based) row key is not persistent, so this won't work correct with insertion/deletion

        • 1. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
          Ilya Shaikovsky Master

          Was not sure while initial discussing with Nick, but finally agree with the main point about different definitions inconvinience (mean ajaxKeys at table and reRender at component) So I think that the way which Nick suggested is pretty good for such partial iteration components updates definitions.


          render="form:table[12]:group" ...

          looks good and I want to add that it also looks better for me not to use
          render="#{bean.keys}" ...
          

          and produce something like "form:table[12]:group, form:table[13]:group" in value binding, but use
          render="form:table[#{bean.keys}]group" ...
          

          and handle the result which Nick already posted:
          form:table[12, 13]:group
          

          at table level.

          Also we could add handling as discussed with Nick for some short definitions like

          
          render="form:table[#{bean.keys}]" ...
          
          or to be more clear
          
          render="form:table[#{bean.keys}]@row" ...
          render="form:tree[#{bean.keys}]@node" ...
          render="form:tree[#{bean.keys}]@group" ...
          
          


          Such definitions just allow us to update precise row/nodes instead of precise cells.

          Question for the case if we leave "ajaxKeys": do we need to add extra set of AJAX keys for auto-updated elements, e.g. messages updatable only in the processed rows?


          I still vote for the idea which will allows us to keep functionality of the ajax auto updatable outputs in tables/trees but not requires any additional code from the developers. I mean to keep current calls to model if need to check for such updatable elements. But we could just limit this functionality with some attribute like updateNestedRenderedAreas(just for example) bollean attribute which will allow us to tell the table that it doesn't contains such elements. And have it turned off by default to avoid such reports as RF-3341.

          I think that another use-case that this approach doesn't cover is of very low importance and we can safely ignore it. That is the case of controlling updates for particular row components in a more agile manner, e.g. to update component "a" for rows 1, 3, 5 and component "b" for rows 1, 2, 3.


          Can't also imagine common usecase where it could be needed within single request. So seems could not to paid much attention. And b.t.w. seems possible in current proposed notation for example with
          render="form:table[#{bean.keys}]componentA, form:table[#{bean.keys}]componentB" ...
          


          • 2. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
            Nick Belaevski Master

            Talking about updateNestedRenderedAreas, we have even better solution - JSF system events allow parent components to be notified of all their descendants, so tables can track instances of AjaxOutput implicitly.

            But what mechanism will be used to define set of rows for these outputs - ajaxKeys or smth. else?

            • 3. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
              Ilya Shaikovsky Master

              If the attribute is defined as true - them will be just added automatically to RenderedAreas after created (as usual outputPanels outside of table) I think. And if not - them will be ignored. Or I'm missing some question idea?

              • 4. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                Nick Belaevski Master

                We do not attribute, because we can detect nested ajax outputs easy and this doesn't require collections intialization.

                • 5. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                  Jay Balunas Master

                  At first I was not sure about this idea, but I am beginning to like it better. I want to walk through some of my concerns and understand this better.

                  One of my concerns is that users need to know exactly what data is updated so they can define the correct values. e.g.:

                  render="form:table[12]:group"


                  Knowing that "12" needs to be updated is very specific. I suppose this can be handled by using EL as Ilya shows here:

                  render="form:table[#{bean.keys}]:group"


                  Then what rows should be updated can be handled programmaticly. The other parts of the notation would also need to be set this way.

                  render="form:table[#{bean.keys}]:#{bean.idToUpdate}"


                  This would give us control of both row and component to render. I wonder how other component libraries handle this type of situation, do we have any comparisons?

                  Understanding this notation might also be a hurdle, but I would be interested in what other people think.

                  • 6. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                    Jay Balunas Master

                    Properly handling insertion and deletion of rows is an area I need to understand better as well.

                    You mention in post that there are issues here. I assume this is because the state is stored for the current table and modifying that will cause the data and state to not be in sync any longer.

                    Currently to insert, remove rows of data the whole table needs to be rendered - correct? I'm also assuming this is the case whether the row was inserted, removed by a user action or if the data model updates underneath.

                    I think that it is common use-case, as applications always want to show the latest data. I always think of a stock price table like yahoo's where the data updates regularly without rerendering the whole table. Or perhaps Ilya's example with push http://in.relation.to/Bloggers/UsingRichFacesPushAndDataTableAjaxKeysForPartialTablesUpdates but with the # of fruits changing with each vote. Perhaps showing the top 5 voted fruit out of a list of 20. The rows shown would be changing, possibly with each vote and we would not want to rerender the whole table.

                    I'm not saying I have the answer - just think this is something to consider :-)

                    • 7. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                      Jay Balunas Master

                       

                      render="form:table[#{bean.keys}]@row" ...
                      render="form:tree[#{bean.keys}]@node" ...
                      render="form:tree[#{bean.keys}]@group" ...
                      


                      I like this idea and it seems similar to the notation that JSF 2 is using like @form, and @this.

                      @row would update the whole row - but what would @node update, or @group?

                      • 8. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                        Jay Balunas Master

                        A few areas I am not clear about and would like more description:

                        Question for the case if we leave "ajaxKeys": do we need to add extra set of AJAX keys for auto-updated elements, e.g. messages updatable only in the processed rows?


                        and the "updateNestedRenderedAreas" discussion. I might need an example to understand this better.

                        Also I need to understand how this effects tree processing - as you mention there are issues there with this approach. Can we find a unified approach that works for both tree's and tables?

                        Alex was involved in some discussions with the EG related to collection based components. I wonder what his thought on this is?

                        • 9. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                          Nick Belaevski Master

                           

                          "jbalunas@redhat.com" wrote:
                          You mention in post that there are issues here. I assume this is because the state is stored for the current table and modifying that will cause the data and state to not be in sync any longer.

                          Yes, example of this problem is list of data changing between requests. For items in the list client IDs are created according to indexes of items and that's the problem.

                          "jbalunas@redhat.com" wrote:
                          Currently to insert, remove rows of data the whole table needs to be rendered - correct? I'm also assuming this is the case whether the row was inserted, removed by a user action or if the data model updates underneath.

                          Yes, that's right.

                          "jbalunas@redhat.com" wrote:
                          I think that it is common use-case, as applications always want to show the latest data. I always think of a stock price table like yahoo's where the data updates regularly without rerendering the whole table. Or perhaps Ilya's example with push http://in.relation.to/Bloggers/UsingRichFacesPushAndDataTableAjaxKeysForPartialTablesUpdates but with the # of fruits changing with each vote. Perhaps showing the top 5 voted fruit out of a list of 20. The rows shown would be changing, possibly with each vote and we would not want to rerender the whole table.

                          Me either thinks it's a common use case we need to support, and not only for tables, but for repeat components. Good example of this can be tabs created/removed dynamically by the user without re-rendering the whole tab panel.

                          • 10. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                            Nick Belaevski Master

                             

                            "jbalunas@redhat.com" wrote:
                            render="form:table[#{bean.keys}]@row" ...
                            render="form:tree[#{bean.keys}]@node" ...
                            render="form:tree[#{bean.keys}]@group" ...
                            


                            I like this idea and it seems similar to the notation that JSF 2 is using like @form, and @this.

                            @row would update the whole row - but what would @node update, or @group?


                            @node - can be used for tree
                            @group - probably for rich:columnGroup

                            • 11. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                              Jay Balunas Master

                              Is there any updates to this functionality and plan?

                              I thing the notation would be good, and personally think it is easier to understand than ajaxKeys :-)

                              • 12. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                                Ilya Shaikovsky Master

                                Spend some time on final detailed discussion of the feature with Nick and here are the results:

                                 

                                ajaxKeys will be removed from iteration components

                                 

                                render="tableId:rowKey:cellId" or render="tableId:#{controller.rowKeysSet}:cellId" should be used to update table cells.

                                pay attention that actuall cells and not just content inside will be updated. That was not available in 3.3.x.

                                 

                                render="cellId" could be used for updates of table cells inside the row where request was risen.

                                 

                                render="tableId:rowKey" or render="tableId:#{controller.rowKeysSet}" shoud be used for updates for the whole rows.

                                 

                                next keywords should be added for table components:

                                • @row - render="@row". updates current row. Available only in context of row requests.
                                • @column - render="@column". Updates current column. Available only in context of some cell requests.
                                • @body - render="tableId:@body". updates table body. render="@body" short notation available in context of requests from the table
                                • @header - render="tableId:@header". updates table body. render="@header" short notation available in context of requests from the table
                                • @footer - render="tableId:@header". updates table body. render="@header" short notation available in context of requests from the table

                                 

                                Auto-updatable components (messages, outputPanels):

                                We will look for such component only in context of  row current request(considering limitToList). So for requests exetrnal to table - them should be listed in render explicitly.

                                If some community feedback on adding old 3.3.x "feature" of updating all such components will appear - we will allow to define it through additional attribute I mentioned earlier in the thread.

                                • 13. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                                  Jay Balunas Master

                                  Excellent!

                                   

                                  Some comments/questions

                                   

                                  • Assuming any part of "tableId:#{controller.rowKeysSet}:cellId" could be variable?

                                  • "Available only in context of row/cell requests."
                                    • Could you provide an example?
                                  • For @header @footer do you mean they update header and footer respectively?
                                    • Not sure if you just have a typo?
                                  • For the auto-updateable part
                                    • This is like an assumed "limittolist"?
                                    • When you say "we will look for such components only..." 
                                      • When will you look?
                                      • I think I understand what you are trying to solve, but not how?

                                   

                                  Other than that I think this is going to be good!!

                                  • 14. Re: RichFaces 4.0: Controlling AJAX updates for iteration co
                                    Ilya Shaikovsky Master
                                    Assuming any part of "tableId:#{controller.rowKeysSet}:cellId" could be variable?

                                    Yes. This sample written in this way just to show implementation fully analogous to using ajaxKeys.

                                     

                                    "Available only in context of row/cell requests."

                                    I'm not sure maybe choosen not good keywords. So it's not so clear. As you could see from the description the @row keyword used to udate current row for example. So:

                                     

                                    <rich:column>
                                         <a4j:commandButton render="@row">
                                    </rich:column>
                                    

                                     

                                    updates all the row in which button was clicked.

                                    And this

                                     

                                    <a4j:commandButton render="@row">
                                    <rich:table>
                                    <rich:column>
                                    ....
                                    

                                     

                                    is forbidden.

                                     

                                    For @header @footer do you mean they update header and footer respectively?

                                    Yes it's just typo.

                                    1 2 Previous Next