11 Replies Latest reply on Jun 23, 2008 2:59 PM by ssilvert

    Invoking a4j:commandLink with a4j:actionparam

      Hi,

      I'm writing a JSFUnit test to click an a4j:commandLink that is nested in a dataTable. The code looks similar to the following:

      <rich:dataTable var="entry" ... />
       ...
       <rich:column>
       <a4j:commandLink id="tableLink" action="nextPage" ... />
       <a4j:actionparam name="param" value="entry.id" />
       </a4j:commandLink>
       </rich:column>
       ...
      </rich:dataTable>
      

      To click the link in the first row of the table, the JSFUnit code does something similar to this (rfClient is an instance of RichFacesClient):
      rfClient.ajaxSubmit("0:tableLink");
      

      I would assume that the actionparam would be included in the request, but it is not. I have to manually include the actionparam in the java code by calling: ajaxSubmit(String componentID, Map<String,String> userParams). Is this expected?

      Thanks.

      Justin.

        • 1. Re: Invoking a4j:commandLink with a4j:actionparam
          ssilvert

          <a4j:actionparam> should work. I know we have a test for it in the JSFUnit tests suite, but not one that is inside a dataTable. I'm not sure why the dataTable would make a difference.

          I know I sound like a broken record here, but this one will have to wait for the new HtmlUnit version of JSFUnit (see "New AJAX Support" thread at the top of this forum). The HtmlUnit lead told me today that he has found the problem with RichFaces compatibility and he's cleaning things up now. So it should be ready soon.

          Stan

          • 2. Re: Invoking a4j:commandLink with a4j:actionparam

            Alright, I'll keep an eye out for it. Thanks.

            Justin.

            • 3. Re: Invoking a4j:commandLink with a4j:actionparam

              So I believe I was originally mistaken on how component IDs are generated from within a dataTable. In my original post I noted that I was trying to access the first row in the table like so:

              rfClient.ajaxSubmit("0:tableLink");
              

              I used "0:" here because I thought the number represented the table row index. Through the course of writing other tests it was brought to my attention that the numerical value is the row key, not row index (I'm using a RichFaces ExtendedDataModel to display data in the table... if that matters).

              I believe component ID's from within a dataTable are generated with the following suffix: <table ID>:<row key>:<component ID>. I've been using this strategy to access other components within dataTables (e.g., a boolean checkbox).

              However, whenever I try to access an a4j:commandLink within a dataTable, I always run into a ComponentIDNotFoundException:
              org.jboss.jsfunit.facade.ComponentIDNotFoundException:
              No component ID was found for dataModelTable:10:tableLink
              at org.jboss.jsfunit.facade.ClientIDs.findClientID(ClientIDs.java:172)
              at org.jboss.jsfunit.richfaces.Ajax4jsfClient.setRowIndicies(Ajax4jsfClient.java:92)
              at org.jboss.jsfunit.richfaces.Ajax4jsfClient.ajaxSubmit(Ajax4jsfClient.java:168)
              at org.jboss.jsfunit.richfaces.Ajax4jsfClient.ajaxSubmit(Ajax4jsfClient.java:152)
              ...
              

              The HTML source clearly shows a link with that ID, so I'm puzzled as to why I can't access it. I've tried using RichFacesClient and Ajax4jsfClient to no avail.
              <a href="#" id="mainDisplay:content:form:dataModelTable:10:tableLink" ...
              

              Even if I spell out the entire ID from the HTML above, I still see the exception.

              With all that said, I have no idea why doing an ajaxSubmit("0:tableLink") works at all. Go figure.

              Any ideas?

              Justin.

              • 4. Re: Invoking a4j:commandLink with a4j:actionparam

                More info:

                I changed the link to an h:commandLink (ajax wasn't required to begin with) and I still see the same ComponentIDNotFoundException.

                It appears that the client only knows about the last link with suffix "tableLink" on the page (even though there are 10 of them). If I execute the following snippet it outputs only the last link in the table (e.g., the 10th one).

                log.info(client.getClientIDs().findClientID("tableLink"));
                

                I would expect a DuplicateClientIDException here.

                Justin.

                • 5. Re: Invoking a4j:commandLink with a4j:actionparam
                  ssilvert

                   

                  "jinpsu" wrote:
                  (I'm using a RichFaces ExtendedDataModel to display data in the table... if that matters).

                  I think it might matter. Currently, the way I gather all the ID's is to walk the component tree and call getClientID() on each component. If the component is a UIData, then I collect all the components in the displayed rows.

                  Apparently, that's not working in your case. Can you give me some more information on how you are using the RichFaces ExtendedDataModel?

                  Stan

                  • 6. Re: Invoking a4j:commandLink with a4j:actionparam

                    You're right, Stan, it does matter. Apparently the framework was calling setRowIndex(int) followed by getRowKey() on the data model to build the component ID. The setRowIndex() method needs to be responsible for also setting the row key (for the subsequent call to getRowKey()).

                    My problem was that I wasn't setting the row key in setRowIndex() because the example code on the RichFaces live demo indicates that set(get)RowIndex methods are not used at all:

                    http://livedemo.exadel.com/richfaces-demo/richfaces/dataTable.jsf (click the "Extended Data Model" tab then the "View AuctionDataModel.java Source" link at the bottom).

                    • 7. Re: Invoking a4j:commandLink with a4j:actionparam
                      ssilvert

                      Just to be clear, is there something I need to change on my end or is this just a problem with the way you were using ExtendedDataModel?

                      Stan

                      • 8. Re: Invoking a4j:commandLink with a4j:actionparam

                        Well, the documentation was a little misleading on the RichFaces side which is why I didn't implement the routine correctly. I don't believe JSFUnit code was erroneous here.

                        As for the original problem of no actionparam being posted in the ajax request, I believe I was incorrectly using RichFacesClient instead of Ajax4jsfClient for the ajaxSubmit(). However, when I use Ajax4jsfClient, the code chokes trying to find the AjaxRendererUtils class:

                        org/ajax4jsf/framework/renderer/AjaxRendererUtils
                        
                        java.lang.NoClassDefFoundError: org/ajax4jsf/framework/renderer/AjaxRendererUtils
                        at org.jboss.jsfunit.richfaces.Ajax4jsfClient.buildEventOptions(Ajax4jsfClient.java:239)
                        at org.jboss.jsfunit.richfaces.Ajax4jsfClient.ajaxSubmit(Ajax4jsfClient.java:171)
                        at org.jboss.jsfunit.richfaces.Ajax4jsfClient.ajaxSubmit(Ajax4jsfClient.java:152)
                        ...
                        

                        In RichFaces 3.2.X, AjaxRendererUtils is in the org.ajax4jsf.renderkit package. Is this a known issue being fixed in the HtmlUnit release?

                        • 9. Re: Invoking a4j:commandLink with a4j:actionparam
                          ssilvert

                           

                          "jinpsu" wrote:

                          In RichFaces 3.2.X, AjaxRendererUtils is in the org.ajax4jsf.renderkit package. Is this a known issue being fixed in the HtmlUnit release?

                          It won't matter with the new HtmlUnit stuff. HtmlUnit will actually execute the javascript code and you won't need a RichFacesClient. You will just use the JSFClientSession for everything.

                          For now, you will use the RichFacesClient instead of Ajax4jsfClient. The Ajax4jsfClient understands the old Ajax4jsf API that was hosted at java.net.

                          Stan



                          • 10. Re: Invoking a4j:commandLink with a4j:actionparam

                            Gotcha, thanks!

                            Justin

                            • 11. Re: Invoking a4j:commandLink with a4j:actionparam
                              ssilvert

                               

                              "stan.silvert@jboss.com" wrote:
                              It won't matter with the new HtmlUnit stuff. HtmlUnit will actually execute the javascript code and you won't need a RichFacesClient. You will just use the JSFClientSession for everything.

                              Stan

                              For the record, it looks like the new HtmlUnit-based JSFUnit will still need a RichFacesClient of some sort. That client will be a LOT simpler than the old one though. For complex RichFaces components, the component is sometimes rendered as several controls with generated client ID's that are not obvious from the markup. So to "click" one of these controls it will help to have an API that knows what to expect.

                              Otherwise, the JSFUnit developer would have to inspect the rendered HTML to write a test. And we want to avoid that if possible.

                              Stan