2 Replies Latest reply on Jan 7, 2012 11:42 PM by Diego Andres Cerrano

    How to include dinamically xhtml pages via ajax

    Diego Andres Cerrano Newbie

      Hello everybody!. I'm a new guy in richfaces, and I need to know how to include a page dinamically without reload the main page.

      My main page looks like:

       

      <h:body>
             <rich:panel id="main_content"> 
                   <f:facet name="header">AJAX LOADING VS FULL LOADING</f:facet>  
                   <f:subview id="main_view"> 
                         <ui:include src="./#{page.value}" />
                  </f:subview>  
            </rich:panel> 
      </h:body>
      

      By default, the value of page.value is "list.xhtml", which is a xhtml file that has a list of item (<a4j:commandLink />).

      My list.xhtml is:

       

      <h:body> 
          <h:form> 
               <rich:panel> 
                     <f:facet name="header">#{page.value}</f:facet> 
                     <h:outputText value="I'm a list page!" /> 
               </rich:panel> 
               <c:forEach begin="1" end="10" varStatus="i"> 
                     <a4j:commandLink value="Item #{i.index}" 
                                                 action="#{page.setValue('detail')}" 
                                                 render="main_content" > 
                     </a4j:commandLink> 
                </c:forEach> 
            </h:form> 
      </h:body>
      

       

      The idea of list.xhtml is to list items of <a4j:commandLink> and when the user clicks on any item, the value of the backing bean page.value will be "detail.xhtml", and then only the <rich:panel id="main_content"> must to be reloaded, not all the document. The main_content won't be the list.xhtml anymore(because page.value is "detail.xhtml").

       

      The detail.xhtml file is:

      <h:body> 
           <h:form> 
               <a4j:commandLink value="Back -> Ajax reload" 
                                            action="#{page.setValue('list')}" 
                                            render="main_content" > 
               </a4j:commandLink>  
               <rich:panel> 
                     <f:facet name="header">#{page.value}</f:facet>  
                     <h:outputText value="I'm a detail page!" /> 
               </rich:panel> 
            </h:form> 
      </h:body>
      

       

       

      So, when the user clicks on link "Back", the main_content will be reloaded with "list.xhtml" (again via ajax).

       

      When I click on any a4j:commandLink, the value of the backing bean page.value changes successfully, but the main content is not reRendered, even the title of the <rich:panel id="main_content"> changes, but not the content.

       

      Is correct to code this way when you want to change pages dinamically via ajax?

       

      My backing bean "page" is:

       

      import javax.faces.bean.ManagedBean;
      import javax.faces.bean.SessionScoped;
      
      
      /**
       *
       * @author diego
       */
      @ManagedBean
      @SessionScoped
      public class Page {
          private String value = "list.xhtml";
      
          public String getValue() {
              return value;
          }
      
          public void setValue(String page) {
              if (page.compareTo("list") == 0) {
                  this.value = "list.xhtml";
              } else if (page.compareTo("detail") == 0) {
                  this.value = "detail.xhtml";
              } 
          }
      }
      

       

      I hope someone has the right answer, I will really appreciate it.

       

      P.D. Sorry for my english.

        • 1. Re: How to include dinamically xhtml pages via ajax
          Brendan Healey Master

          Unfortunately this is very hard to do. What you'll find is that you can include another page

          using an EL expression that just outputs information, but if you have any UICommand components

          they won't work. Variations are that the commandLink/Button will only work on the first click,

          won't work on the first click, or won't work at all. It does all depend on what you need to do

          within the content that's included with ui:include using an EL expression for the src attribute.

          If you don't need buttons that execute backing bean methods you'll probably be ok.

           

          I experimented at length with this and did manage to get it to work but only by disabling partial

          state saving (this can be done on a per view basis or for the app as a whole) - this is to work

          around a Mojarra limitation, and even then you need to use Mojarra 2.1 or later. This is clearly

          not a minor change to be made without due consideration.

           

          What I've not tried doing is getting this to work using any richfaces ajax magic, when I last looked

          at this I was just using basic jsf tags. There have been a number of recent posts on this forum

          where people have tried using a4j:outputPanel ajaxRendered="true" and other richfaces tags but

          I'm not aware of anyone having said "yes I've got it working", but you probably ought to check

          yourself.

           

          Even though I had got this working for some months it suddenly stopped working, and I'd spent so

          much time already that I couldn't be bothered looking into it any more, and just reverted to an

          "include everything all the time" approach.

           

          The extremely lengthy Mojarra JIRA is here: http://java.net/jira/browse/JAVASERVERFACES-1313

          and although this is marked as resolved fixed in v2.1, my own experience contradicts that.

           

          If you decide to proceed with further investigation can I suggest a couple of things:

           

          - use Mojarra 2.1.3/2.1.4

          - it's probably easier to start off without the c:forEach

          - if you're going to have commandButtons or links in the included content, make sure they work (fire

            an action or actionListener method) on the first, second and subsequent clicks.

           

          I'd be very interested to hear how you get on.

           

          Regards,

          Brendan.

          • 2. Re: How to include dinamically xhtml pages via ajax
            Diego Andres Cerrano Newbie

            Hi Brendan! Thanks for your answer, you saved me lot of time with the link http://java.net/jira/browse/JAVASERVERFACES-1313.

            "Variations are that the commandLink/Button will only work on the first click, won't work on the first click, or won't work at all" you right,  in some case works, in other cases not, and I don't know why because I haven't read enough about JSF and richfaces.

            But I have found a "solution" to my problem(yes, you will see that is a bad solution but I have no choice, I have to finish my work anyway)

             

            The main page is:

             

            <html xmlns="http://www.w3.org/1999/xhtml" 
                       xmlns:a4j="http://richfaces.org/a4j"
                       xmlns:h="http://java.sun.com/jsf/html"
                       xmlns:f="http://java.sun.com/jsf/core"
                       xmlns:rich="http://richfaces.org/rich">
                <h:head>
                        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
                        <title>Main page</title>
                        <script type="text/javascript" src="./resources/js/ajax.js"></script>
               </h:head>
            
               <h:body onload="reloadPage('list.xhtml')">
                     <!--a4j:status is just to avoid :Uncaught ReferenceError: RichFaces is not defined--> <a4j:status /> 
                     <rich:panel id="main_content"> 
                            <f:facet name="header">AJAX LOADING VS FULL LOADING</f:facet> 
                             <!--innerHTML of div will be changed with ajax request--> 
                             <div id="contenido"></div> 
                     </rich:panel>
               </h:body>
            </html>
            

             

            The list.xhtml is:

             

            <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                                    xmlns:ui="http://java.sun.com/jsf/facelets"
                                    xmlns:h="http://java.sun.com/jsf/html"
                                    xmlns:rich="http://richfaces.org/rich"
                                    xmlns:a4j="http://richfaces.org/a4j"
                                    xmlns:f="http://java.sun.com/jsf/core"
                                    xmlns:c="http://java.sun.com/jsp/jstl/core">
                 <h:head> </h:head>
                 <h:body>
                        <h:form>
                               <rich:panel>
                                     <f:facet name="header">LIST</f:facet>
                                     <h:outputText value="I'm a list page!" /><br /> 
                                     <c:forEach begin="1" end="10" varStatus="i">
                                           <a4j:commandLink value="Item #{i.index}"
                                                                        action="#{detail.setDescription(i.index)}"
                                                                        oncomplete="reloadPage('detail.xhtml')" /> <br />
                                     </c:forEach>
                                </rich:panel>
                         </h:form>
                  </h:body>
            </ui:composition>
            
            

            The detail.xhtml is:

                

            <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                                         xmlns:ui="http://java.sun.com/jsf/facelets"
                                         xmlns:h="http://java.sun.com/jsf/html"
                                         xmlns:rich="http://richfaces.org/rich"
                                         xmlns:a4j="http://richfaces.org/a4j"
                                         xmlns:f="http://java.sun.com/jsf/core"
                                         xmlns:c="http://java.sun.com/jsp/jstl/core">
                <h:head> </h:head>
                <h:body>
                       <h:form>
                              <a4j:commandLink value="Back -> Ajax reload" onclick="reloadPage('list.xhtml')" />
                               <rich:panel>
                                     <f:facet name="header">DETAIL</f:facet>
                                     <h:outputText value="Hi! I'm a detail of item #{detail.description}" />
                               </rich:panel>
                        </h:form>
                 </h:body>
            </ui:composition>
            

            The backing bean

             

            import javax.faces.bean.ManagedBean;
            import javax.faces.bean.SessionScoped;
            
            /**
             * @author diego
             */
            @ManagedBean
            @SessionScoped
            public class Detail {
                private String description;
            
                public String getDescription() {
                    return description;
                }
            
                public void setDescription(String description) {
                    this.description = description;
                }
            }
            
            

            And the ajax.js

            function reloadPage(page) {

                var peticion = null;

                if (window.XMLHttpRequest){

                    peticion = new XMLHttpRequest();

                }

                else if(window.ActiveXObject) {

                    peticion = new ActiveXObject("Microsoft.XMLHTTP");

                }

             

             

                if (peticion == null)

                    return;

                peticion.onreadystatechange = resul;

                peticion.open('POST','./faces/' + page, true);

                peticion.send(null);

             

             

                function resul(){

                    if(peticion.readyState == 4 && peticion.status == 200){

                        document.getElementById("contenido").innerHTML = peticion.responseText;

                    }

                }

            }

             

            Notice that the ajax.js code is not efficient, but you can improve it.

            This example works perfect to me, but I don't think so that is the recommended way to do this.

            If you find a good way to do the same, please let me know.

             

            Regards from Paraguay, thanks again!