ICEfaces
  1. ICEfaces
  2. ICE-9677

ace:dataTable - The entire table is returned in the update upon row selection/deselection

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: EE-3.3.0.GA_P01
    • Fix Version/s: 4.0.BETA, EE-3.3.0.GA_P02, 4.0
    • Component/s: ACE-Components
    • Labels:
      None
    • Environment:
      Mojarra 2.1.6
    • Assignee Priority:
      P1
    • Salesforce Case Reference:
    • Affects:
      Compatibility/Configuration
    • Workaround Exists:
      Yes
    • Workaround Description:
      Hide
      Set PARTIAL_STATE_SAVING to true:

          <context-param>
              <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
              <param-value>true</param-value>
          </context-param>
      Show
      Set PARTIAL_STATE_SAVING to true:     <context-param>         <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>         <param-value>true</param-value>     </context-param>

      Description

      A basic ace:dataTable uses two ace:ajax tags, one for select, the other for deselect. Upon selection/deselection only the updated row should be returned in the update, as this is all that changes. Normally this works fine but under certain conditions this is not the case.

      Conditions:
       - The following context parameter is set in the web.xml:
          <context-param>
              <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
              <param-value>false</param-value>
          </context-param>
       - There needs to be two ace:ajax tags used, for example:
                          <ace:ajax event="select" render="@all" execute="@all" />
                          <ace:ajax event="deselect" render="@all" execute="@all" />

      If one ajax tag is removed then only the selected/deselected row is returned in the response even with P_S_S set to false.
      1. update-comparison-18-11-2013.txt
        3 kB
        Arran Mccullough

        Activity

        Hide
        Arran Mccullough added a comment -

        Attached a sample test case that shows this issue. Note: The war file needs the icefaces.jar, icefaces-ace.jar, and icefaces-compat.jar from the current icefaces3 trunk to run.

        Steps:

        • Load welcomeICEfaces.jaf
        • With some developer tools open, double click a row to select/deselect and review what is returned in the update.

        I also attached a txt file that shows the comparison with different settings/code.

        Show
        Arran Mccullough added a comment - Attached a sample test case that shows this issue. Note: The war file needs the icefaces.jar, icefaces-ace.jar, and icefaces-compat.jar from the current icefaces3 trunk to run. Steps: Load welcomeICEfaces.jaf With some developer tools open, double click a row to select/deselect and review what is returned in the update. I also attached a txt file that shows the comparison with different settings/code.
        Hide
        J Bloemer added a comment -

        A long explanation but this was the result of our research. Unfortunately just adding an ID to the script doesn't work because there are other regressions.

        <script type="text/javascript">var widget_gF_names = new ice.ace.DataTable('
        gF:names', {"formId":"gF","widgetVar":"widget_gF_names","clickableHeaderSorting":true,"height":240,"selectionMode":"single","dblclickSelect":true,"instantSelect":true,"scrollable":true,"liveScroll":false,"scrollStep":0,"scrollLimit":4,"scrollIE8Like7":false,
        "behaviors":{"select":

        {"source":"gF:names","execute":'@all',"render":'@all',"event":"select"}

        ,"deselect":

        {"source":"gF:names","execute":'@all',"render":'@all',"event":"deselect"}

        }});</script>

        This script is encoded by DataTableRenderer.encodeScript() using CoreRenderer.encodeClientBehaviors() to encode any ace:ajax client behaviors in the DataTable context.

        Now, there's nothing special about that, BUT:

        This happens if there are more than one ace:ajax behaviors defined:
        Apparently encodeClientBehaviors() is not deterministic, hence every time it's called it renders the behaviors in a different order.

        Usually this shouldn't be a problem, because the order of behaviors in the javascript call are commutative, nevertheless: For DOMUtils.compareNodes() this is a nodeDiff which causes an AJAX update in the response.

        Until now this shouldn't be that bad, because the response would just contain the script itself which is kind of unnecessary but not that much of an issue.

        Now, this little snippet of code:

        if (!compareNodes(config, nodeDiffs, oldChildNodes.item,
        newChildNodes.item)) {
        String id = getNodeId(newNode);
        if (null != id)

        { //subtree was unable to process the diff nodeDiffs.cursor = startCursor; nodeDiffs.add(new ReplaceOperation(newNode)); diffDebug(config, "replace: diff from below ", newNode); return true; }


        return false;
        }

        Says that to replace a certain part of the DOM, an ID is needed. If the ID can't be found, the parent component within the DOM is replaced. Unfortunately the script has no ID defined and even worse: The parent DIV is the DataTable itself
        --> The whole table is updated instead of single rows
        --> the response size is doubled.

        Show
        J Bloemer added a comment - A long explanation but this was the result of our research. Unfortunately just adding an ID to the script doesn't work because there are other regressions. <script type="text/javascript">var widget_gF_names = new ice.ace.DataTable(' gF:names', {"formId":"gF","widgetVar":"widget_gF_names","clickableHeaderSorting":true,"height":240,"selectionMode":"single","dblclickSelect":true,"instantSelect":true,"scrollable":true,"liveScroll":false,"scrollStep":0,"scrollLimit":4,"scrollIE8Like7":false, "behaviors":{"select": {"source":"gF:names","execute":'@all',"render":'@all',"event":"select"} ,"deselect": {"source":"gF:names","execute":'@all',"render":'@all',"event":"deselect"} }});</script> This script is encoded by DataTableRenderer.encodeScript() using CoreRenderer.encodeClientBehaviors() to encode any ace:ajax client behaviors in the DataTable context. Now, there's nothing special about that, BUT: This happens if there are more than one ace:ajax behaviors defined: Apparently encodeClientBehaviors() is not deterministic, hence every time it's called it renders the behaviors in a different order. Usually this shouldn't be a problem, because the order of behaviors in the javascript call are commutative, nevertheless: For DOMUtils.compareNodes() this is a nodeDiff which causes an AJAX update in the response. Until now this shouldn't be that bad, because the response would just contain the script itself which is kind of unnecessary but not that much of an issue. Now, this little snippet of code: if (!compareNodes(config, nodeDiffs, oldChildNodes.item , newChildNodes.item )) { String id = getNodeId(newNode); if (null != id) { //subtree was unable to process the diff nodeDiffs.cursor = startCursor; nodeDiffs.add(new ReplaceOperation(newNode)); diffDebug(config, "replace: diff from below ", newNode); return true; } return false; } Says that to replace a certain part of the DOM, an ID is needed. If the ID can't be found, the parent component within the DOM is replaced. Unfortunately the script has no ID defined and even worse: The parent DIV is the DataTable itself --> The whole table is updated instead of single rows --> the response size is doubled.
        Hide
        Arturo Zambrano added a comment -

        Committed fix to 4.0 trunk at revision 38790. Made encodeClientBehaviors() render the list of behaviours deterministically (sorted alphabetically by event name).

        Since the behaviours are stored as a HashMap, and we know that hash maps don't make any guarantees regarding order, the list of behaviours was being rendered in different orders. This was fixed by sorting the key set before iterating over the behaviours.

        Adding a client id to the script tag is not an option, because, like many components, the data table needs to be completely re-rendered whenever there's a change in the settings.

        Thanks to the customer for their detailed analysis.

        Show
        Arturo Zambrano added a comment - Committed fix to 4.0 trunk at revision 38790. Made encodeClientBehaviors() render the list of behaviours deterministically (sorted alphabetically by event name). Since the behaviours are stored as a HashMap, and we know that hash maps don't make any guarantees regarding order, the list of behaviours was being rendered in different orders. This was fixed by sorting the key set before iterating over the behaviours. Adding a client id to the script tag is not an option, because, like many components, the data table needs to be completely re-rendered whenever there's a change in the settings. Thanks to the customer for their detailed analysis.
        Hide
        Ken Fyten added a comment -

        The clientBehaviors are now ordered deterministically.

        Show
        Ken Fyten added a comment - The clientBehaviors are now ordered deterministically.
        Hide
        Arturo Zambrano added a comment -

        r38821:
        Committed fix to 3.3 EE maintenance branch.

        Show
        Arturo Zambrano added a comment - r38821: Committed fix to 3.3 EE maintenance branch.

          People

          • Assignee:
            Arturo Zambrano
            Reporter:
            Arran Mccullough
          • Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: