Announcement Announcement Module
Collapse
No announcement yet.
Webflow returns full page instead of tiles fragment Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Webflow returns full page instead of tiles fragment

    Hi,

    I'm having problems refreshing fragments in webflow. In order to test my understanding, I've build a simple demo app which consists of one page with three parts - a menu, a body and a footer. Each part prints out the current time. The menu also has a refresh link which is meant to refresh the body. If this was working correctly, the time in the body tile would be later than the time in the menu and footer tiles

    Of course, this isn't working (otherwise I wouldn't be here typing this post on Sunday morning!). Checkng the result returned to the browser with the use of firebug, the complete page is returned instead of just the body fragment.

    As I understand it, a complete page is returned if javascript is disabled, but the refresh request is being made as an ajax call, so this doesn't look to be the problem. If anyone could point out where I'm going wrong, I'd really appreciate it. I'm using Spring 2.5.6, webfow 2.0.9 (have tried 2.0.6 also), tiles 2.1.0 and spring-js 2.0.9 (also tried 2.0.5)

    Here's the tiles page definition:

    Code:
    <tiles-definitions>
      <definition name="welcome" template="/WEB-INF/jsp/template.jsp">
          <put-attribute name="menu" value="/WEB-INF/jsp/menu.jsp"/>
          <put-attribute name="body" value="/WEB-INF/jsp/welcome.jsp"/>
          <put-attribute name="footer" value="/WEB-INF/jsp/footer.jsp"/>
      </definition>
    </tiles-definitions>
    Here's the template.jsp

    Code:
      <table cellpadding="5" cellspacing="5" border="1" width="100%">
          <tr>
              <td id="left" width="150px"><tiles:insertAttribute name="menu" /></td>
              <td id="right"><tiles:insertAttribute name="body" /></td>
          </tr>
          <tr>
              <td colspan="2" id="bottom"><tiles:insertAttribute name="footer" /></td>
          </tr>
      </table>
    Here's the welcome page jsp - this is the section that I'm trying to refresh as a fragment

    Code:
    <div id="body">
        Welcome: <%=new java.util.Date()%>
    </div>
    Here's the menu.jsp - this contains the javascript that sets up the async call and initialises the callback on that's meant to swap out the body fragment with the result returned from the server:

    Code:
    <form:form method="GET" id="refreshForm">
    	<a id="refresh" href="#">Refresh</a>
    	<script type="text/javascript">
    		Spring.addDecoration(new Spring.AjaxEventDecoration({
    		   elementId: "refresh", <%-- get the page element with this ID and add an event handler to it that will submit the form on the event  --%>
    		   formId: "refreshForm", <%-- when the event occurs, submit the form with this ID --%>
    		   event: "onclick", <%-- The type of event to handle --%>
    		   params: { _eventId: "refreshPage" }
    		}));
    	</script>
    </form:form>
    Here's the webflow - this basically has one view-state containing an internal transition that's meant to return the body fragment:

    Code:
    <view-state id="start" view="welcome_page" redirect="false">
    	<transition on="refreshPage">
    		<render fragments="body" />
    	</transition>		
    </view-state>
    The only thing left to describe is the webflow and tiles configuration:

    Code:
        <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
            <property name="definitions">
                <list>
                    <value>/WEB-INF/tiles/pages.xml</value>
                </list>
            </property>
        </bean>
        
        <bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
            <property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView"/>
        </bean>
    
    	<!-- Enables FlowHandler URL mapping -->
    	<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
    	    <property name="flowExecutor" ref="flowExecutor" />
    	</bean>
    	
    	<!-- Maps request paths to flows in the flowRegistry;
    	     e.g. a path of /hotels/booking looks for a flow with id "hotels/booking" -->		
    	<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
    	    <property name="flowRegistry" ref="flowRegistry"/>
    	    <property name="order" value="0"/>
    	</bean>  
    	
    	<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry"/>
    
    	<webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
    		<webflow:flow-location path="/WEB-INF/classes/flows/results/results.xml" />
    	</webflow:flow-registry>
    	
    	<webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="viewFactoryCreator" />
    
    	<bean id="viewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
    		<property name="viewResolvers" ref="viewResolver" />
    	</bean>
    	
    	<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
            <property name="basename" value="views" />
        </bean>
    This configuration is pretty much standard stuff, with the exception of the view resolver I'm using. This is just so I can define the views in a views.properties file. Inside this file there's the following mapping:

    Code:
    welcome_page.class=org.springframework.web.servlet.view.tiles2.TilesView
    welcome_page.url=welcome
    I'd really appreciate it if someone would point out where I'm going wrong.

  • #2
    Fixed!

    OK, figured out what to do. Firstly I changed the configuration so that the viewFactoryCreator now creates a FlowAjaxTilesView tiles view resolver:

    Code:
        <bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
            <property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView"/>
        </bean>
    
        <webflow:flow-registry id="flowRegistry" flow-builder-services="flowBuilderServices">
            <webflow:flow-location path="/WEB-INF/classes/flows/results/results.xml" />
        </webflow:flow-registry>
    	
        <webflow:flow-builder-services id="flowBuilderServices" view-factory-creator="viewFactoryCreator" />
    
        <bean id="viewFactoryCreator" class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
            <property name="viewResolvers"  ref="tilesViewResolver" />
        </bean>
    And secondly, I added the fragments param into the async request in the menu.jsp like so:

    Code:
    <form:form method="GET" id="refreshForm">
    	<a id="refresh" href="#">Refresh</a>
    	<script type="text/javascript">
    		Spring.addDecoration(new Spring.AjaxEventDecoration({
    		   elementId: "refresh", <%-- get the page element with this ID and add an event handler to it that will submit the form on the event  --%>
    		   formId: "refreshForm", <%-- when the event occurs, submit the form with this ID --%>
    		   event: "onclick", <%-- The type of event to handle --%>
    		   params: { _eventId: "refreshPage", fragments:"body" }
    		}));
    	</script>
    </form:form>
    The thing about this one is that I read in another post that this wasn't required when using webflow, as it can be determined from the render fragments property in the transition (unfortunately can't find the post to check I got this 100% correct). But when I stepped through the code, the fragments string was always null, and adding this back in sorts it out. Maybe it's a bug in the version of webflow/tiles that I'm using.

    Comment

    Working...
    X