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

        Greg Dick created issue -
        Hide
        Deryk Sinotte added a comment -

        I ran the trunk against Liferay and see the same thing. Looks to be a problem with rendering out the JavaScript behaviours for the ice.ace.Datatable (formatted slightly for readability):

        behaviors:{select:{
        source:"A7601:listenerForm:carTableSingleRow",
        execute:"A7601:listenerForm:carTableSingleRow listenerForm:eventLog",
        render:"A7601:listenerForm:carTableSingleRow listenerForm:eventLog",
        event:"select"}}

        You can see that the source id has the portlet namespace (A7601) and the first render/execute id has the namespace but the second render/execute id does not have the namespace. This causes the problem of not being able to find it. It's not quickly clear to me where this all gets handled in the rendering code so we may need to assign the JIRA to somebody in the component team.

        Show
        Deryk Sinotte added a comment - I ran the trunk against Liferay and see the same thing. Looks to be a problem with rendering out the JavaScript behaviours for the ice.ace.Datatable (formatted slightly for readability): behaviors:{select:{ source:"A7601:listenerForm:carTableSingleRow", execute:"A7601:listenerForm:carTableSingleRow listenerForm:eventLog", render:"A7601:listenerForm:carTableSingleRow listenerForm:eventLog", event:"select"}} You can see that the source id has the portlet namespace (A7601) and the first render/execute id has the namespace but the second render/execute id does not have the namespace. This causes the problem of not being able to find it. It's not quickly clear to me where this all gets handled in the rendering code so we may need to assign the JIRA to somebody in the component team.
        Hide
        Deryk Sinotte added a comment -

        Actually I see now that the <ace:ajax> tag simply has these hard-coded in. For example, in datatableListener.xhtml:

        <ace:ajax event="select" execute="@this listenerForm:eventLog" render="@this listenerForm:eventLog" />

        So while @this can be properly processed to include the namespace, we probably aren't processing the hardcoded values.

        Show
        Deryk Sinotte added a comment - Actually I see now that the <ace:ajax> tag simply has these hard-coded in. For example, in datatableListener.xhtml: <ace:ajax event="select" execute="@this listenerForm:eventLog" render="@this listenerForm:eventLog" /> So while @this can be properly processed to include the namespace, we probably aren't processing the hardcoded values.
        Ken Fyten made changes -
        Field Original Value New Value
        Assignee Nils Lundquist [ nils.lundquist ]
        Ken Fyten made changes -
        Salesforce Case []
        Fix Version/s EE-3.0.0.GA_P01 [ 10327 ]
        Fix Version/s 3.2 [ 10338 ]
        Assignee Priority P1
        Affects Version/s 3.1 [ 10312 ]
        Hide
        Deryk Sinotte added a comment -

        Raw ids should probably use the following API:

        String encodedId = externalContext.encodeNamespace(theRawIdtoEncode);

        This should provide the namespace in front so that "blah" becomes "namespace:blah". However, it might not add the colon so you might need to use:

        String encodedId = externalContext.encodeNamespace(":" + theRawIdtoEncode);

        Show
        Deryk Sinotte added a comment - Raw ids should probably use the following API: String encodedId = externalContext.encodeNamespace(theRawIdtoEncode); This should provide the namespace in front so that "blah" becomes "namespace:blah". However, it might not add the colon so you might need to use: String encodedId = externalContext.encodeNamespace(":" + theRawIdtoEncode);
        Ken Fyten made changes -
        Salesforce Case []
        Fix Version/s EE-3.0.0.GA_P01 [ 10327 ]
        Affects [Compatibility/Configuration]
        Assignee Priority P1 P2
        Assignee Nils Lundquist [ nils.lundquist ] Mark Collette [ mark.collette ]
        Hide
        Deryk Sinotte added a comment -

        Another way to describe the problem. Give that the ace:ajax behaviour has these attributes:

        <ace:ajax event="select" execute="@this listenerForm:eventLog" render="@this listenerForm:eventLog" />

        So ace:ajax is handling these "raw ids" that point to valid components on the page. On a portal page however, with the portlet bridge, all components get namespaced to ensure that they are unique.

        The scripts for the behaviours end up rendering out what was noted before. The @this values are correct but the "raw" values are not:

        execute:"A7601:listenerForm:carTableSingleRow listenerForm:eventLog",
        render:"A7601:listenerForm:carTableSingleRow listenerForm:eventLog",

        Above you can see that the namespace A7601 was applied to the @this values but not to the "raw" values. The component it refers to though does have an id of A7601:listenerForm:eventLog.

        So somewhere in ace:ajax classes, "listenerForm:eventLog" has to be processed or encoded to contain the namespace. This has been a common issue when one component "refers" to another component in some way on a portal page. However, I'm not certain where the fix should go as we're not really referring to the id of a component (which would normally just get handled transparently by JSF and the portlet bridge).

        Show
        Deryk Sinotte added a comment - Another way to describe the problem. Give that the ace:ajax behaviour has these attributes: <ace:ajax event="select" execute="@this listenerForm:eventLog" render="@this listenerForm:eventLog" /> So ace:ajax is handling these "raw ids" that point to valid components on the page. On a portal page however, with the portlet bridge, all components get namespaced to ensure that they are unique. The scripts for the behaviours end up rendering out what was noted before. The @this values are correct but the "raw" values are not: execute:"A7601:listenerForm:carTableSingleRow listenerForm:eventLog", render:"A7601:listenerForm:carTableSingleRow listenerForm:eventLog", Above you can see that the namespace A7601 was applied to the @this values but not to the "raw" values. The component it refers to though does have an id of A7601:listenerForm:eventLog. So somewhere in ace:ajax classes, "listenerForm:eventLog" has to be processed or encoded to contain the namespace. This has been a common issue when one component "refers" to another component in some way on a portal page. However, I'm not certain where the fix should go as we're not really referring to the id of a component (which would normally just get handled transparently by JSF and the portlet bridge).
        Hide
        Mark Collette added a comment -

        What happens if instead of:

        execute="@this listenerForm:eventLog"

        You use a leading colon:

        execute="@this :listenerForm:eventLog"

        Show
        Mark Collette added a comment - What happens if instead of: execute="@this listenerForm:eventLog" You use a leading colon: execute="@this :listenerForm:eventLog"
        Repository Revision Date User Message
        ICEsoft Public SVN Repository #31396 Wed Oct 10 16:31:45 MDT 2012 deryk.sinotte ICE-8492: add namespace to raw id attributes of ace:ajax component
        Files Changed
        Commit graph MODIFY /icefaces3/trunk/icefaces/ace/component/src/org/icefaces/ace/util/ComponentUtils.java
        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).
        Repository Revision Date User Message
        ICEsoft Public SVN Repository #31809 Fri Oct 26 18:00:19 MDT 2012 deryk.sinotte ICE-8492: adjust findComponents logic and some markup ids to better support portlets
        Files Changed
        Commit graph MODIFY /icefaces3/trunk/icefaces/samples/showcase/showcase/src/main/webapp/resources/examples/ace/menuBar/menuBarMultiColumn.xhtml
        Commit graph MODIFY /icefaces3/trunk/icefaces/samples/showcase/showcase/src/main/webapp/resources/examples/ace/date/datenavigator.xhtml
        Commit graph MODIFY /icefaces3/trunk/icefaces/samples/showcase/showcase/src/main/webapp/resources/examples/ace/dataExporter/dataExporterRows.xhtml
        Commit graph MODIFY /icefaces3/trunk/icefaces/samples/showcase/showcase/src/main/webapp/resources/examples/ace/date/dateajax.xhtml
        Commit graph MODIFY /icefaces3/trunk/icefaces/ace/component/src/org/icefaces/ace/util/ComponentUtils.java
        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.
        Migration made changes -
        Assignee Mark Collette [ mark.collette ] Deryk Sinotte [ deryk.sinotte ]
        Migration made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Resolution Fixed [ 1 ]
        Migration made changes -
        Resolution Fixed [ 1 ]
        Status Resolved [ 5 ] Reopened [ 4 ]
        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
        Ken Fyten made changes -
        Status Reopened [ 4 ] Resolved [ 5 ]
        Resolution Fixed [ 1 ]
        Ken Fyten made changes -
        Status Resolved [ 5 ] Closed [ 6 ]
        Assignee Priority P2 [ 10011 ]

          People

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

            Dates

            • Created:
              Updated:
              Resolved: