ICEfaces
  1. ICEfaces
  2. ICE-8492

showcase-portlet Data table examples not working for row selection events

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.1
    • Fix Version/s: 3.2
    • Component/s: Sample Apps
    • Labels:
      None
    • Environment:
      ICEFaces + WebSphere Portal
    • Affects:
      Compatibility/Configuration

      Description

      The Ajax update code associated with the data table selection code doesn't appear to update the server. The problem is visible in Ace data table listener and Ace data table row selector demo pages. The page has an area which is supposed to reflect what has been recently selected. The examples don't show any updates whatever at the moment.

      In the row selector example, Console shows the following message on selection event:
      [23/08/12 10:16:56:092 PDT] 00000033 ComponentUtil I Cannot find component with identifier "selectForm:status" in view.

      In the data table listener example, console shows the following message on selection event:
      [23/08/12 10:18:04:834 PDT] 0000003e ComponentUtil I Cannot find component with identifier "listenerForm:eventLog" in view.

        Activity

        Hide
        Deryk Sinotte added a comment - - edited

        Adding the leading colon does not help as the Axxxx is the id of the top container provided by the portlet bridge. So part of the actual id.
        The main problem in this case is that our ace:ajax component takes raw ids for it's attribute values but does not process them to work with environments like portlets that namespace those ids. For example, in the ace:dataTable - Row Selector Example, the component markup looks like this:

            <ace:ajax event="select" render="@this selectForm:status" execute="@this" />

        While the special @ references are handled fine, the inclusion of raw ids like "selectForm:status" are not processed to include the namespace. This causes the org.icefaces.ace.component.ajax.AjaxBehaviourRenderer to render out the related widget code like so:

            var widget_A6324_selectForm_instantCarTableSingleRow = 
                 new ice.ace.DataTable("A6324:selectForm:instantCarTableSingleRow",
                                       {formId:"A6324:selectForm",
                                        widgetVar:"widget_A6324_selectForm_instantCarTableSingleRow",
                                        clickableHeaderSorting:true,
                                        selectionMode:"single",
                                        instantSelect:true,
                                        behaviors:{select:
                                        {source:"A6324:selectForm:instantCarTableSingleRow",
                                         execute:"A6324:selectForm:instantCarTableSingleRow",
                                         render:"A6324:selectForm:instantCarTableSingleRow selectForm:status",
                                         event:"select"}}});

        You can see that the elements like @this get renderered out with the correct portlet namespace but the hard-coded id values like "selectForm:status" do not.
        I tracked down the handling of these ids to the org.icefaces.ace.util.ComponentUtils.findClientIds method. This is where the @this type elements are added into the JSON string as well as the raw component ids. To improve the behaviour for raw ids, I added a call to a new method, encodeNameSpace(), that attempts to properly encode the namespace for any raw ids that are encountered. With this change in place, the render behaviour now renders out as:

            render:"A6324:selectForm:instantCarTableSingleRow A6324:selectForm:status"

        And clicking on the rows properly updates the status. Note that, with Development mode turned on, we still see the following messages:

        Oct 10, 2012 9:49:51 PM org.icefaces.ace.util.ComponentUtils findClientIds
        INFO: Cannot find component with identifier "A6324:selectForm:status" in view.

        Not sure why this is the case. It's not related to portlets because the same message occurs in the non-portlet version of showcase:

        Oct 10, 2012 3:13:32 PM org.icefaces.ace.util.ComponentUtils findClientIds
        INFO: Cannot find component with identifier "selectForm:status" in view.

        and it occurs in both Mojarra and MyFaces. It seems as if the search almost always fails. In any event, the change to encode the namespace allows the client-side widget scripts to work properly.

        Show
        Deryk Sinotte added a comment - - edited Adding the leading colon does not help as the Axxxx is the id of the top container provided by the portlet bridge. So part of the actual id. The main problem in this case is that our ace:ajax component takes raw ids for it's attribute values but does not process them to work with environments like portlets that namespace those ids. For example, in the ace:dataTable - Row Selector Example, the component markup looks like this: <ace:ajax event= "select" render= "@ this selectForm:status" execute= "@ this " /> While the special @ references are handled fine, the inclusion of raw ids like "selectForm:status" are not processed to include the namespace. This causes the org.icefaces.ace.component.ajax.AjaxBehaviourRenderer to render out the related widget code like so: var widget_A6324_selectForm_instantCarTableSingleRow = new ice.ace.DataTable( "A6324:selectForm:instantCarTableSingleRow" , {formId: "A6324:selectForm" , widgetVar: "widget_A6324_selectForm_instantCarTableSingleRow" , clickableHeaderSorting: true , selectionMode: "single" , instantSelect: true , behaviors:{select: {source: "A6324:selectForm:instantCarTableSingleRow" , execute: "A6324:selectForm:instantCarTableSingleRow" , render: "A6324:selectForm:instantCarTableSingleRow selectForm:status" , event: "select" }}}); You can see that the elements like @this get renderered out with the correct portlet namespace but the hard-coded id values like "selectForm:status" do not. I tracked down the handling of these ids to the org.icefaces.ace.util.ComponentUtils.findClientIds method. This is where the @this type elements are added into the JSON string as well as the raw component ids. To improve the behaviour for raw ids, I added a call to a new method, encodeNameSpace(), that attempts to properly encode the namespace for any raw ids that are encountered. With this change in place, the render behaviour now renders out as: render: "A6324:selectForm:instantCarTableSingleRow A6324:selectForm:status" And clicking on the rows properly updates the status. Note that, with Development mode turned on, we still see the following messages: Oct 10, 2012 9:49:51 PM org.icefaces.ace.util.ComponentUtils findClientIds INFO: Cannot find component with identifier "A6324:selectForm:status" in view. Not sure why this is the case. It's not related to portlets because the same message occurs in the non-portlet version of showcase: Oct 10, 2012 3:13:32 PM org.icefaces.ace.util.ComponentUtils findClientIds INFO: Cannot find component with identifier "selectForm:status" in view. and it occurs in both Mojarra and MyFaces. It seems as if the search almost always fails. In any event, the change to encode the namespace allows the client-side widget scripts to work properly.
        Hide
        Mark Collette added a comment - - edited

        The console warning is because "A6324:selectForm:status" is a relative search string that searches from the dataTable, and A6324 cannot be found in the current naming container, which is the dataTable. It's the same reason that the form ("selectForm") couldn't be found from the dataTable. Keep in mind that a relative search string could be many naming containers deep, so just pre-pending the portlet namespace to a relative id won't work in all cases, and only does in this test case. Luckily the code passes throug ids it can't find. The correct solution is to use the portlet id from EL, as part of an absolute search string. I don't know the proper EL expression, so I'll make one up here and you can substitute the correct one.
        :#

        {request.portletId}:selectForm:status
        Which would give us:
        <ace:ajax event="select" render="@this :#{request.portletId}

        :selectForm:status" execute="@this" />
        With this, there shouldn't be need of a code change in ComponentUtils.findClientIds. To remove the warning, but again not solve the problem for other applications, one would have needed to pre-pend the : before the encodeNameSpace part of the string.

        Show
        Mark Collette added a comment - - edited The console warning is because "A6324:selectForm:status" is a relative search string that searches from the dataTable, and A6324 cannot be found in the current naming container, which is the dataTable. It's the same reason that the form ("selectForm") couldn't be found from the dataTable. Keep in mind that a relative search string could be many naming containers deep, so just pre-pending the portlet namespace to a relative id won't work in all cases, and only does in this test case. Luckily the code passes throug ids it can't find. The correct solution is to use the portlet id from EL, as part of an absolute search string. I don't know the proper EL expression, so I'll make one up here and you can substitute the correct one. :# {request.portletId}:selectForm:status Which would give us: <ace:ajax event="select" render="@this :#{request.portletId} :selectForm:status" execute="@this" /> With this, there shouldn't be need of a code change in ComponentUtils.findClientIds. To remove the warning, but again not solve the problem for other applications, one would have needed to pre-pend the : before the encodeNameSpace part of the string.
        Hide
        Deryk Sinotte added a comment - - edited

        This brings up a couple of points. Before I added the code to encode the namespace, the assumption was that the raw id would be in a format for searching the JSF component tree instead of a format that the client would eventually use. That is, the app developer would enter something like:
        formId:componentId
        because that's how the component appears in the markup as well. But for the find logic to work it really needed to be:
        :potentialNamespace:formId:componentId
        Assuming the component was found, it would render out the client id so that the scripts on the page would work:
        potentialNamespace:formId:componentId
        If the component wasn't found, it would just "fall through" and render out the original raw attribute:
        formId:componentId
        The showcase application as it stood before the fix was always failing to find the component (servlet and portlet) as it wasn't in the correct form. It just happened to work in the servlet mode because the raw id (formId:componentId) was already in the format that the client script required. However in portlets, this isn't the case. It can't find the component and the raw id is not in the correct form.
        So there are two strategies. We can document what you need to enter for the raw id so that it works in various situations. However, the EL expression you'd need to do this is portlet specific and requires the portlet bridge to be there. Neil has the usage documented in the Liferay Faces documentation found here:
        http://central.maven.org/maven2/com/liferay/faces/liferay-faces-doc/3.1.0-ga1/liferay-faces-doc-3.1.0-ga1.pdf
        The example snippet looks like this:
        <h:form>
        <portlet:namespace var="mynamespace" />
        <h:outputText var="namespace=#

        {mynamespace}" />
        </h:form>
        So in our app it would be:
        <portlet:namespace var="mynamespace" />
        ... :#{mynamespace}

        :selectForm:status" ...
        This has the side-effect of making the app markup portlet-specific. Additionally, to get the find mechanism to work, it has to be in the JSF format.
        The code I added to do the processing to encode the namespace skips the middle man and simply renders out the id as it's required on the client. I don't think the logic to find the actual component in the tree and get its id is required at all (unless there are cases where it needs to find something inside a repeating structure or something more complex which I'm unaware of).
        I think it's much easier and intuitive to simply tell the developer to add the ids as they already appear in the markup than to get them to add the portlet-specific EL with the additional ":" to make the search absolute. (again, unless there are use cases where that's the only way).

        Show
        Deryk Sinotte added a comment - - edited This brings up a couple of points. Before I added the code to encode the namespace, the assumption was that the raw id would be in a format for searching the JSF component tree instead of a format that the client would eventually use. That is, the app developer would enter something like: formId:componentId because that's how the component appears in the markup as well. But for the find logic to work it really needed to be: :potentialNamespace:formId:componentId Assuming the component was found, it would render out the client id so that the scripts on the page would work: potentialNamespace:formId:componentId If the component wasn't found, it would just "fall through" and render out the original raw attribute: formId:componentId The showcase application as it stood before the fix was always failing to find the component (servlet and portlet) as it wasn't in the correct form. It just happened to work in the servlet mode because the raw id (formId:componentId) was already in the format that the client script required. However in portlets, this isn't the case. It can't find the component and the raw id is not in the correct form. So there are two strategies. We can document what you need to enter for the raw id so that it works in various situations. However, the EL expression you'd need to do this is portlet specific and requires the portlet bridge to be there. Neil has the usage documented in the Liferay Faces documentation found here: http://central.maven.org/maven2/com/liferay/faces/liferay-faces-doc/3.1.0-ga1/liferay-faces-doc-3.1.0-ga1.pdf The example snippet looks like this: <h:form> <portlet:namespace var="mynamespace" /> <h:outputText var="namespace=# {mynamespace}" /> </h:form> So in our app it would be: <portlet:namespace var="mynamespace" /> ... :#{mynamespace} :selectForm:status" ... This has the side-effect of making the app markup portlet-specific. Additionally, to get the find mechanism to work, it has to be in the JSF format. The code I added to do the processing to encode the namespace skips the middle man and simply renders out the id as it's required on the client. I don't think the logic to find the actual component in the tree and get its id is required at all (unless there are cases where it needs to find something inside a repeating structure or something more complex which I'm unaware of). I think it's much easier and intuitive to simply tell the developer to add the ids as they already appear in the markup than to get them to add the portlet-specific EL with the additional ":" to make the search absolute. (again, unless there are use cases where that's the only way).
        Hide
        Deryk Sinotte added a comment - - edited

        Re-opening as the original logic done for portlets was not quite correct. Instead of always encoding the namespace, we now only do it if the component can't be found using the provided id. This allows it to search within the existing naming container before moving on to a absolute search in the root container.

        Show
        Deryk Sinotte added a comment - - edited Re-opening as the original logic done for portlets was not quite correct. Instead of always encoding the namespace, we now only do it if the component can't be found using the provided id. This allows it to search within the existing naming container before moving on to a absolute search in the root container.
        Hide
        Ken Fyten added a comment -

        ICE-8492: adjust findComponents logic and some markup ids to better support portlets
        ICE-8492: add namespace to raw id attributes of ace:ajax component

        Show
        Ken Fyten added a comment - ICE-8492 : adjust findComponents logic and some markup ids to better support portlets ICE-8492 : add namespace to raw id attributes of ace:ajax component

          People

          • Assignee:
            Deryk Sinotte
            Reporter:
            Greg Dick
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: