1 2 Previous Next 21 Replies Latest reply on Apr 5, 2011 10:25 AM by coenos

    Back button and shopping cart contents

    coenos

      Hi,


      I have a very simple scenario but I can't get it to work. Looked for some days now on forums and articles but I didn't find a solution (call me stupid :)


      So here's the scenario:


      Page 1 : categories , user selects a category, navigate to page 2
      Page 2 : products, populated based on selected category, user adds a product, the shopping cart contents are updated, navigate to page 2
      Page 2 again: user can add another product. shopping cart now shows 2 products.



      Now, when I press the back button, I navigate back to page 2, but the shopping cart is emptying the products. At least, the SFSB shopping cart contains the products but the page is not refreshed correctly. It just shows the previous states.


      How can I get this to work? I have JSF navigation which all work fine, but the back button issue is breaking my brain.


      Thanks for you help,
      Coen


        • 1. Re: Back button and shopping cart contents
          lvdberg

          Hi,


          have you tried solving this with an action on page entry (defined in pages.xml) ?



          Leo

          • 2. Re: Back button and shopping cart contents
            matkapx

            It looks like you have problem with Bijection,
            Is your beans Conversation Scoped ?  Well you said , SFSB which i understand is , State Full Session Bean,  you can use you seam debug page, to see what object are stored in your conversation context.


            • 3. Re: Back button and shopping cart contents
              coenos

              Hi,


              I do have products.pages.xml files.




              <?xml version="1.0" encoding="UTF-8"?>
              <page xmlns="http://jboss.com/products/seam/pages" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.1.xsd"
                   view-id="/custom/products.xhtml" no-conversation-view-id="/login.xhtml" >
              
                   <!-- <header name="Cache-Control" value="no-cache, no-store, max-age=0, 
                        must-revalidate" /> -->
              
                   <begin-conversation join="true" flush-mode="MANUAL" />
              
                   <navigation from-action="#{prodSelCon.addProduct(prod)}">
                        <rule if-outcome="success">
                             <!-- 
                             <end-conversation/>
                              -->
                             <redirect view-id="/custom/products.xhtml" />
                        </rule>
                        <redirect />
                   </navigation>     
              
              </page>
              
              



              I removed the end-conversation during tweaking.


              Here is my productSelection controller.




              @Name("prodSelCon")
              @Scope(ScopeType.SESSION)
              public class ProductSelectionController {
              
                   @In @Out
                   ShoppingCart shoppingCart;
                   
                   Set<Product> products = new HashSet<Product>();
              
                   @Logger
                   private Log log;
              
                   public String addProduct(Product product) {
                        shoppingCart.addProduct(product);
                        
                        products.add(product);
                        log.info("--------------------  adding new product "
                                  + product.getName() + " --------------------  "+products.size());
              
                        return "success";
                   }
              
                   public ShoppingCart getShoppingCart() {
                        
                        log.info("--------------------  GETTING CARD  --------------------  ");
                        
                        return shoppingCart;
                   }     
              }
              



              Here is my SFSB cart




              @Stateful
              @Name("shoppingCart")
              @Scope(ScopeType.SESSION)
              @AutoCreate
              public class ShoppingCartImpl implements ShoppingCart {
              
                   @Logger
                   private Log log;
              
                   private List<Product> products = new ArrayList<Product>();
                   private Consumer consumer;
              
                   @PostConstruct
                   public void initialize() {
              
                        log.info("------------------------- SHOPPINGCART CREATED ----------------------------");
              
                        //products = new ArrayList<Product>();
                   }
              
                   @Override
                   public String addProduct(Product product) {
              
                        products.add(product);
                        
                        log.info("------------------------- ADDED PRODUCT TO CART  ----------------------------"
                                  + products.size());
                        
                        return "success";
                   }
              
                   @Override
                   public void removeProduct(Product product) {
                        products.remove(product);
              
                   }
              
                   @Override
                   public void setConsumer(Consumer consumer) {
                        this.consumer = consumer;
              
                   }
              
                   @Override
                   public Consumer getConsumer() {
                        return this.consumer;
                   }
              
                   @Remove
                   @Override
                   public void remove() {
              
                   }
              
                   @Destroy
                   @Override
                   public void destroy() {
                        //products = null;
                        //consumer = null;
                   }
              
                   @Override
                   public List<Product> getProducts() {
                        return products;
                   }
                   
                   @Override
                   public int getTotalProducts(){
                        return products.size();
                   }     
              
              }
              



              Hope this sheds some light. Thanks for your help,
              Coen



              • 4. Re: Back button and shopping cart contents
                coenos

                I also added this entry to the main pages.xml.




                <page view-id="/custom/products.xhtml" conversation-required="true">
                          <navigation from-action="#{prodSelCon.addProduct(prod)}">
                               <rule if-outcome="success">
                                    <!-- <end-conversation/> -->
                                    <redirect view-id="/custom/products.xhtml" />
                               </rule>
                               <redirect />
                          </navigation>
                     </page>
                
                



                • 5. Re: Back button and shopping cart contents
                  lvdberg

                  Hi,


                  some simple guessing, because we don't have the page..


                  It seems to work, because your beans are in the sessions scope, which lasts until  the user log-out/disconnects.


                  In your ProductSelectionController you have a getShoppingCard-method, so it seems that you've incluuded an additional layer on top of the SFSB;  Nice when you use Spring or Struts or whatever other action layers, but not necessary when you have Seam. Add all the needed functionallity in your SFSB.


                  Additionally it means that the autocreate is not necessary anymore, because you call the SFSB directly in your view (which autocreates your beans).


                  make it a simple conversation, so change the SFSB to that scope (or just remove the annotation, because it's default).


                  Add a init-method on the SFSB, which is called when you start with your page. Add the action element to your page, and the init-method will called when you first open the page.


                  Consider changing everything to simple POJO (unless you have specific requirements), because the Seam handling of a POJO saves you an additional Interface.


                  Leo

                  • 6. Re: Back button and shopping cart contents
                    coenos

                    Hi Leo,


                    thanks for your reply. Yes indeed a lot is not according to standard, but you are saying it seems to work ?


                    I mean, when I add two products to the cart, and then press the back button, the selectedproducts show no entry because the app is back to the previous page without reloading/refreshing. So it never reloads the shopping cart entries to the page. I see that in the log.


                    Here is the page




                         <ui:define name="topmenu">
                    
                              <ui:debug hotkey="1" rendered="true" />
                    
                              <div id="Container">
                                   <div id="TopMenu">
                                        <ul>
                                             <li>ProductPage</li>
                                             <li>Adress</li>
                                             <li>Enzo</li>
                                             <li>
                                             <h:outputLabel value="total products: #{shoppingCart.totalProducts}" />
                                             </li>
                                        </ul>
                                   </div>
                                   <div id="Outer">
                                        <div id="Header">
                                             <div id="Logo">
                                                  <div id="LogoContainer"></div>
                                             </div>
                                        </div>
                                        <div id="Menu">
                                             <ul>
                                                  <li>Home</li>
                                                  <li>Adress</li>
                                                  <li>Enzo</li>
                                             </ul>
                                        </div>
                                   </div>
                              </div>
                    
                         </ui:define>
                    
                         <ui:define name="content">
                              <div id="Wrapper">
                                   <h:form styleClass="Left">
                                        <rich:dataList var="cat"
                                             value="#{productCategoryRepos.allCategories}" rows="11">
                    
                                             <h:commandLink action="#{prodCon.showProducts(cat.productcatId)}" value="#{cat.name}" />
                                             <br />
                                        </rich:dataList>
                                   </h:form>
                    
                                   <h:form styleClass="Content">
                                        <h:outputLabel value="Products" />
                    
                                        <rich:panel style="height : 704px; width : 577px;">
                                             <f:facet name="header">
                                                  <h:outputText value="Car Store"></h:outputText>
                                             </f:facet>
                    
                                             <rich:dataGrid
                                                  value="#{productCategoryRepos.getProductsByCategoryId(prodCon.productcatId)}"
                                                  var="prod" columns="2" elements="2" width="550px">
                                                  <rich:panel bodyClass="pbody">
                                                       <f:facet name="header">
                                                            <h:outputText value="#{prod.name}"></h:outputText>
                                                       </f:facet>
                                                       <h:panelGrid columns="2">
                                                            <h:panelGroup>
                                                                 <h:outputText value="Name:" styleClass="label"></h:outputText>
                                                                 <h:outputText value="#{prod.name}" />
                                                                 <br />
                                                                 <h:outputText value="webprice:" styleClass="label"></h:outputText>
                                                                 <h:outputText value="#{prod.webprice}" />
                                                                 <br />
                                                                 <h:commandLink action="#{prodSelCon.addProduct(prod)}" id="add"
                                                                      value="Add to Cart" />
                                                                 <br />
                                                            </h:panelGroup>
                                                            <h:graphicImage width="40" height="50"
                                                                 value="/img/Emperor-Palpatine.jpg" />
                                                       </h:panelGrid>
                    
                                                  </rich:panel>
                                                  <f:facet name="footer">
                                                       <br />
                                                       <h:commandLink action="#{prodCon.aktie}" value="KLIK 2" />
                                                  </f:facet>
                                             </rich:dataGrid>
                                        </rich:panel>
                                   </h:form>
                    
                                   <h:form styleClass="Right">
                                        <h:outputText value="Selected Products:" />
                                        <br />
                                        <rich:dataList var="prod" value="#{shoppingCart.products}"
                                             rows="11">
                    
                                             <h:outputText value="#{prod.name}" />
                                             <br />
                                        </rich:dataList>
                                   </h:form>
                    
                              </div>
                         </ui:define>
                    



                    So when I press the back button the shoppingCart.products is not executed.



                    Thanks for your help,
                    Coen

                    • 7. Re: Back button and shopping cart contents
                      lvdberg

                      Hi,


                      try adding the action method to your page. I can see in your page that you have additional beans as repositories, so I assume that you have your persistency there. Keep in mind that Seam injection ONLY works when methods are directly called. So calling a method in a second bean (sucg as the getShoppingCard-method is not useful. As stated, get rid of the unneccesary layers; the SFSB works directly as a controller, so normally there is no need to have additional action layers.


                      Leo.

                      • 8. Re: Back button and shopping cart contents
                        coenos

                        Hi Leo,


                        I do have the action in my page AND in the products.pages.xml. The action is triggered correctly


                        I know I have not programmed very tidy (yet) but technically everything works, injection etc works fine. Only the back button problem exists.


                        When I do the flow again, the shopping cart shows the correct product, so




                        1. categories, select category

                        2. products page : add product to cart, add another product , right column shows two products in the cart

                        3. press back button, now products are shown but right columns shows no selected products (i.e. the page is not refreshed)

                        4. select another category, those products are shown, and the shopping cart entries are there again!



                        So the problem is, why does the back button not refresh the page with the selected shopping cart entries?


                        Thanks for your help,
                        Coenos

                        • 9. Re: Back button and shopping cart contents
                          lvdberg

                          Hi,


                          we're talking about two different things now. You mention the result of an action in the navigation-rule. I mean the addition of an action when you create the view.


                          This is an attribute in the page(s) tag. Examples:




                          <page view-id="/myPage.xhtml"  >
                               <action execute="#{doSomething.init}" if="#{ifNeeded}"/>
                          </page>
                          
                          
                          or
                          
                          <page view-id="/myPage.xhtml" action="#{doSomething.init}"  />



                          Whne you add an action to your page definition, you're sure that something gets executed BEFORE rendering anything.


                          Leo


                          • 10. Re: Back button and shopping cart contents
                            antibrumm.mfrey0.bluewin.ch

                            Hi


                            This sounds for me like a very basic caching issue. Did you check if the browser refetches the page when the back button is used? Normal behavior here is that the browser just displays the cached page.


                            I had a very similar issue with ajax rendered stuff on the page. The browser shows just the initially loaded page, which contains none of the ajax rendered parts. I think you use always standard h:commandbuttons? Then i could guess that the url looks always the same if you do not propagate the conversation id. If the url does not change from request to request i'm not sure if all browsers update the cache properly.


                            As a last resort you could always rerender your shopping cart with an ajax call through the body onload function. This one is called also on the back button usage, even if the page is coming from the cache. As long as your backing bean is in the correct state there should be no issue with that.

                            • 11. Re: Back button and shopping cart contents
                              coenos

                              Hi Martin,


                              indeed, I am wondering, is it a cache issue or my own misconfiguration of my app???


                              Because when I navigate all the way back to the categories, the cart's products are shown. Only when navigating the products pages I have this problem. 


                              But I am reading in a lot of articles that Seam should be able to handle this; handling the correct state using the back button.


                              Thanks,
                              Coenos





                              • 12. Re: Back button and shopping cart contents
                                lvdberg

                                Hi Cone,


                                Personally I think you have an application program as well as a configuration problem. Seam handles the use of the back-button transparantly, and as long as you configure everything as it should be it should work in a stateful and an statlesss environment. However your pages files miss the extra settings, so I assume you have the application handling everything.


                                The second issue is the Scope of your beans. It may work in the prsent context, but you're missing Seam's perfect handling of conversations (also necessary to handle also the Back-button).


                                My advice I can give you at the moment is that you re-consider things and go through the docs on the matter.


                                Leo


                                 

                                • 13. Re: Back button and shopping cart contents
                                  coenos

                                  Hi Leo,


                                  I changed the scope of my beans and added some method to pages.xml.


                                  I added this to pages.xml




                                  <page view-id="/custom/products.xhtml" action="#{shoppingCart.init}" />
                                  




                                  But why should I initialize something that is already initialized, like the Shopping Cart. The Cart contains the correct objects but it is not rerendered. You say that Seam handles the back button transparantly, but the docs don't say how to configure this. I thought I had everything as it should in the products.pages.xml and pages.xml but apparently not.
                                  So that's why I posted my question.


                                  Thanks,
                                  Coenos

                                  • 14. Re: Back button and shopping cart contents
                                    lvdberg

                                    Hi,


                                    from the manual:





                                    8.1.2. Seam and the back button

                                    When JSF or Seam navigation rules are used, Seam lets the user freely navigate via the back,
                                    forward and refresh buttons. It is the responsibility of the application to ensure that conversational
                                    state remains internally consistent when this occurs. Experience with the combination of web
                                    application frameworks like Struts or WebWork - that do not support a conversational model -
                                    and stateless component models like EJB stateless session beans or the Spring framework has
                                    taught many developers that this is close to impossible to do! However, our experience is that
                                    in the context of Seam, where there is a well-defined conversational model, backed by stateful
                                    session beans, it is actually quite straightforward. Usually it is as simple as combining the use
                                    of no-conversation-view-id with null checks at the beginning of action listener methods. We
                                    consider support for freeform navigation to be almost always desirable.
                                    In this case, the no-conversation-view-id declaration goes in pages.xml. It tells Seam to
                                    redirect to a different page if a request originates from a page rendered during a conversation,
                                    and that conversation no longer exists




                                    <page view-id="/checkout.xhtml"
                                    no-conversation-view-id="/main.xhtml"/>
                                    





                                    On the other hand, in the stateful model, using the back button is interpreted as an undefined
                                    transition back to a previous state. Since the stateful model enforces a defined set of transitions
                                    from the current state, the back button is not permitted by default in the stateful model! Seam
                                    transparently detects the use of the back button, and blocks any attempt to perform an action from
                                    a previous, stale page, and simply redirects the user to the current page (and displays a faces
                                    message). Whether you consider this a feature or a limitation of the stateful model depends upon
                                    your point of view: as an application developer, it is a feature; as a user, it might be frustrating!
                                    You can enable backbutton navigation from a particular page node by setting

                                    back=enabled



                                    .

                                    etc. etc.


                                    It's just there (my 2.1.2. version of the doc),


                                    Leo





                                    1 2 Previous Next