6 Replies Latest reply on Sep 2, 2009 11:01 AM by kipod

    s:link conversation propagation "none", page parameters

      Hello all.
      I have a situation in which a <s:link propagation="none"> does not leave the current long-running conversation.


      I should mention right off the start that the view id the link leads to has a <begin-conversation join="true"> in its page descriptor in pages.xml.


      My goal (simple - I'm a newbie):
      You view available products on the productList.xhtml page which is backed up by an EntityQuery<Product>. The page has a search mechanism. You enter search criteria, click search and postback to the same page seeing results. You can click a product's name and be taken to its productDetails.xhtml page. When there, you can click a cancel button, and return to the productList.xhtml page - and if any search criteria was previously entered - it will appear as entered.


      My way about it is to start a long-running conversation when you click the search button at productList.xhtml. Also, I wish to leave this conversation upon clicking a product's name and going to view its details - in order to encapsulate the user's action there in a different, new, conversation.


      I don't want to use conversation nesting, because the parent conversation may end (the user clicks on a clear button for resetting search criteria) and the child one would still need to be intact.



      On productList.xhtml, the conversation is upgraded to a long-running one upon clicking the search button, and it is made temporary again when you click clear :



      <h:commandButton id="search"
             value="#{messages['search']}" >
           <s:conversationPropagation type="join" />
      </h:commandButton>
      
      <s:button id="clear"
           value="#{messages['clear']}"
           action="#{productList.clear}"
           propagation="end" />




      (I'm using an h:commandButton because I want the form to be submitted, and there is no action attribute because I wish to postback on the current page - I'm using EntityQuery's RESTRICTIONS - and it all works fine).



      Still in productList.xhtml, this is the link to go view a specific product's details:
      (surrounded by a dataTable with a valid data model of products, where var="_prd")


      <s:link id="productName"
               value="#{_prd.name}"
                 view="/productDetails.xhtml"
                  propagation="none">
         <f:param name="productId" value="#{_prd.id}"/>
      </s:link>






      The productDetails.xhtml file is backed up by a EntityHome<Product>, and also works fine. It has the following descriptor:




      <page view-id="/productDetails.xhtml">
          <begin-conversation join="true" flush-mode="manual"/>
          <param name="productId" value="#{productHome.id}" converterId="javax.faces.Long" />
      </page>



      I want to start a long-running conversation upon entering the page - the page can actually be accessed from many different places in the application.


      Thing is - I want it to be a new separate conversation from existing ones, yet I am using join="true" because I have ajax validation on the page, e.g. :



      <s:decorate id="nameField" template="layout/edit.xhtml">
           <ui:define name="label">#{messages['name']}</ui:define>
           <h:inputText id="name" required="true" value="#{productHome.instance.name}">
                       <a:support id="onblur" event="onblur" reRender="nameField" />
           </h:inputText>
      </s:decorate>



      If I remove the join="true" from productDetails.xhtml's descriptor - I get an exception due to the app trying to start a long-running conversation where one already exists - that's why the join="true" is there.


      The cancel button on productDetails.xhtml :




      <s:button id="cancel"
           value="#{messages['cancel']}"
           view="/productList.xhtml"
           propagation="end" />






      And the bottom line:


      If your'e in the productsList.xhtml page and enter some search criteria and click search, the results are shown and the conversation indeed becomes a long-running one.



      BUT - if you then click on a product's name and go to view its details, the propagation="none" doesn't hold and when entering productDeatils.xhtml Seam will not start a new separate long-running conversation, but join the existing one.


      This leads to a situation where when you click cancel in the productDetails.xhtml page, the conversation is of course ended, and it is the conversation that held the sought after search criteria...


      Any advice would be great! Thanks.

        • 1. Re: s:link conversation propagation "none", page parameters
          mkiel

          What does the link to productDetails.xhtml that's generated by the s:link component look like in your browser? Does it contain a cid parameter?

          • 2. Re: s:link conversation propagation "none", page parameters

            Hi Marcel, thanks for responding.


            Yes it does contain a cid, for example:


            http://localhost:8080/proj/productDetails.seam?productId=3


            I just realized something very important, which minimizes my worries to something rather small:
            When you click search on the productList.xhtml page a new long-running conversation DOES start (!).


            The trouble is such:
            When you click search on the productList.xhtml the conversation turns long-running let's say it has cid=1.


            If you now click on of the search results, you are taken to productDetails.xhtml properly, and my sought-after new conversation (let's say it has cid=2) is formed.


            Only thing is - how do I return to conversation 1 properly: if you click cancel when in the productDetails.xhtml page, you are taken to


            http://localhost:8080/proj/productList.seam?cid=2&conversationPropagation=end


            Whereas I would like to return to conversation 1, if I manually browse to


            http://localhost:8080/proj/productList.seam?cid=1


            The previously entered search criteria appears...
            Does Seam have some simple way for me to tell it go back to the conversation you previously left ?


            Thanks again.

            • 3. Re: s:link conversation propagation "none", page parameters
              mkiel

              OK, so it looks like the link generation is working as it should (the link only contains your productId parameter and not for example cid=1, which would propagate the conversation).




              Does Seam have some simple way for me to tell it 'go back to the conversation you previously left'?


              I'm not aware of any direct way. Maybe you could store the conversation ID of your product list conversation in the product details conversation by passing it in the URL like your productID and including it in the cancel link. But that's not really elegant - I would rather try to use GET parameters for the search criteria. Then you can also have bookmarkable result pages, and the user won't see any conversation timeouts when returning to the list.

              • 4. Re: s:link conversation propagation "none", page parameters

                I guess you are definitely right, and having the search criteria reside in a conversation is bad practice and is bound to timeout...


                So, now there is NO long-running conversation started when the user clicks search in productList.xhtml :




                <h:commandButton id="search"
                   value="#{messages['search']}"
                   action="/productList.xhtml" />
                                         
                <s:button id="clear"
                   value="#{messages['clear']}"
                   action="#{productList.clear}" />




                There are page parameters for productList.xhtml :



                <page view-id="/productList.xhtml">
                   <param name="name" value="#{productList.name}" />
                   <param name="model" value="#{productList.model}" />
                   ...
                </page>



                (The context variables such as productList.name are used in EntityQuery's RESTRICTION clause, and the search works fine)


                Also, clicking a product's name does not propagate="none" the conversation as before, but:




                <s:link id="productName"
                     value="#{_prd.name}"
                            view="/productDetails.xhtml">
                        <f:param name="productId" value="#{_prd.id}"/>
                </s:link>



                The cancel button on productDetails.xhtml is the same:




                <s:button id="cancel"
                     value="#{messages['cancel']}"
                     view="/productList.xhtml"
                     propagation="end" />




                And ...


                All works, except that when clicking cancel in productDetails.xhtml results in a URL
                such as:


                http://localhost:8080/proj/productList.seam?cid=5&conversationPropagation=end


                and does not include the page params... meaning the search criteria isn't retained
                (sort of back to square one)


                Any thoughts? Thanks a lot for replying!

                • 5. Re: s:link conversation propagation "none", page parameters
                  mkiel

                  Try something like this:


                  pages.xml:


                  <page view-id="/productDetails.xhtml">
                     <param name="searchName" value="#{someProductDetailsComponent.searchName}" />
                     <param name="searchModel" value="#{someProductDetailsComponent.searchModel}" />
                     ...
                  </page>



                  productList.xhtml:


                  <s:link id="productName"
                       value="#{_prd.name}"
                              view="/productDetails.xhtml">
                          <f:param name="productId" value="#{_prd.id}"/>
                          <f:param name="searchName" value="#{productList.name}" />
                          <f:param name="searchModel" value="#{productList.model}" />
                          ...
                  </s:link>



                  productDetails.xhtml:


                  <s:link id="cancel"
                       value="#{messages['cancel']}"
                       view="/productList.xhtml">
                          <f:param name="name" value="#{someProductDetailsComponent.searchName}" />
                          <f:param name="model" value="#{someProductDetailsComponent.searchModel}" />
                          ...
                  </s:link>

                  • 6. Re: s:link conversation propagation "none", page parameters

                    Thank you very much for your reply Marcel,


                    I tried your suggestion, but I realized that manually handling the search parameters this way - letting the search parameters pass from productList.xhtml to productDetails.xhtml and back again to productList.xhtml - is too much of a hassle, and I would like the productDetails.xhtml page to be as oblivious as possible to stuff that doesn't concern it in a logical way...


                    What I ended up doing (hopefully it will stay this way) is indeed using nested conversations and your suggested page parameters. It goes like this:


                    When you click search in productList.xhtml a long-running conversation is started and the page is reloaded with the search criteria:




                    <h:commandButton id="search"
                         value="#{messages['search']}"
                         action="/productList.xhtml">
                         <s:conversationPropagation type="join" />
                    </h:commandButton>



                    I need this long-running conversation in order to hold the search criteria like productList.name.
                    This holding isn't for the productList.xhtml page - it has page parametrs, but for the productDeails.xhtml page (!!!) - it will be loaded in a nested conversation.
                    If the user clicks a product a nested conversation is started:



                    <s:link id="productName"
                         value="#{_prd.name}"
                         view="/productDetails.xhtml"
                         propagation="nest" >
                            <f:param name="productId" value="#{_prd.id}"/>
                    </s:link>
                    



                    This nested conversation knows its parent context variables, and so, when this is rendered on the productDetails.xhtml page :



                    <s:button id="cancel"
                         value="#{messages['cancel']}"
                         view="/productList.xhtml"
                         propagation="end" />



                    The page parameters of productList.xhtml are present in the link's URL.


                    This is the best I've come up with, even though I was hoping to avoid usage of nested conversations, it seems the simplest way about it.


                    Thanks a bunch :)