4 Replies Latest reply on May 18, 2011 6:42 PM by ryneezy.ryan.samiley.live.com

    How to Navigate to Previous Page

    ryneezy.ryan.samiley.live.com

      I'm trying to figure out how to navigate back to a previous page when a user clicks on a Cancel button without using JavaScript and Seam navigation rules. I'm trying not to use navigation rules because a user can come from any view, so I wouldn't know what viewId (s)he came from.


      I looked into raising captureViewId event before a redirect so I can get the previous page. The captureViewId observer would call


      Redirect.instance.().captureCurrentView()



      When a cancel button is clicked it would call


      Redirect.instance().returnToCapturedView()



      This is cumbersome because I'll have to raise the event before every redirect.


      I also looked into the org.jboss.seam.navigation.Pages object because it has a


      getPageStack(String viewId)



      method, unfortunately it wants an viewId argument so it can give me the stack relevant to the page. Can I pass in the currentViewId and assume the Pages will be in historical order?


      The getPageStack() method is also protected, so I'll have to extend the Pages object to get call the method. I can call it inside a custom public popView() method.


      What do you guys think? Is there a better solution?


      Thanks,


      Ryan

        • 1. Re: How to Navigate to Previous Page
          ryneezy.ryan.samiley.live.com

          So I got it somewhat working with this:



          package com.mycoolcompany.navigation;
          
          import java.util.List;
          
          import org.jboss.seam.faces.Redirect;
          import org.jboss.seam.navigation.Page;
          
          @Scope(value=APPLICATION)
          @BypassInterceptors
          @Name(value="org.jboss.seam.navigation.pages")
          @Install(precedence=20,
                   classDependencies="javax.faces.context.FacesContext")
          @Startup
          public class Pages extends org.jboss.seam.navigation.Pages {
               public Pages() {
                    super();
               }
               
               public void popView() {
                    final String currentViewId = getCurrentViewId();
                    List<Page> pageStack = getPageStack(currentViewId);
                    
                    final int stackSize = pageStack.size();
                    if (stackSize < 2) {
                         // Cannot go back to previous page when there is no previous page. Minimum stack size is 2.
                         return;
                    }
                    
                    final int prevPageIndex = stackSize - 2;
                    Page prevPage = pageStack.get(prevPageIndex);
                    final String prevPageViewId = prevPage.getViewId();
                    
                    Redirect redirect = Redirect.instance();
                    redirect.setViewId(prevPageViewId);
                    redirect.execute();
                    
               }
          
          }



          The problem is when I have navigation rules with from view-id with a star.


          <page view-id="*">
              <navigation from-action="#{myBean.myAction}">
                 <!-- Some redirects -->
              </navigation>
          
              <navigation from-action="#{myOtherBean.myAction}">
                 <!-- Some More redirects -->
              </navigation>
          
               <!-- More navigation rules -->
          </page>



          The prevPageViewId always resolves as star because I guess that's what seam picked as the previous view-id. That means I have to back and update all my navigation rules so it won't use any view id for each action.


          What am I missing? What's another solution?






          • 2. Re: How to Navigate to Previous Page
            cosmo

            How about getting the referring page? A quick google glimpse gave me this.

            • 3. Re: How to Navigate to Previous Page
              ryneezy.ryan.samiley.live.com

              Thanks for the advice Aldo, the link you provided me helped a lot.


              Using the referer didn't work with the cancel button because it was giving me the current page's URL due to the post back.


              I had to define a page action in pages.xml




              <page view-id="/pages/myPage.xhtml">
                <action execute="#{myBean.captureReferer}" on-postback="false"/>
              </page>



              In the Bean:




              import java.io.IOException;
              import javax.faces.context.FacesContext;
              import org.apache.commons.lang.StringUtils;
              
              public class MyBean {
                private String httpReferer;
              
                public MyBean() { }
                
                public void captureReferer() {
                  httpReferer =
                    FacesContext.getCurrentInstance().getExternalContext().getRequestHeaderMap().get("referer");
                }
              
                public void cancel() {
                  if (StringUtils.isEmpty(httpReferer)) {
                    return;
                  }
                        
                  try {
                    FacesContext.getCurrentInstance().getExternalContext().redirect(httpReferer);
                             
                  } catch (IOException ioe) {
                    log.warn(String.format("Error redirecting to %s", httpReferer));
                  }
                }
              }



              • 4. Re: How to Navigate to Previous Page
                ryneezy.ryan.samiley.live.com

                Oh by the way, I just found out this solution does not work with IE because IE has some bugs with the referer. I also read that the referer is easily spoofed so I had to modify the code somewhat.


                I added an @Observer annotation to the captureReferer method and raised a captureViewId event before the redirect. Instead of capturing the referer, I captured the current view-id.


                The cancel now just has

                <redirect view-id="#{myBean.previousViewId}"/>



                But otherwise if you know your users are never going to use IE, the previous solution works ;)