Announcement Announcement Module
Collapse
No announcement yet.
Spring AJAX calls to logical Tiles views using AjaxUrlBasedViewResolver Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring AJAX calls to logical Tiles views using AjaxUrlBasedViewResolver

    Hello,

    I'm attempting to use Web Flow's JS module to perform AJAX calls to tile views, so far I can't seem to get individual Tile's to refresh via the AJAX calls...the AJAX calls are being performed all right, some calls are effectively executing the instructions on the server, but the tile never refreshes. On another AJAX call using Web Flow's JS module I get a NullPointerException on the class
    org.springframework.js.ajax.tiles2.AjaxTilesView.f lattenAttributeMap(AjaxTilesView.java:116)

    Here is the setup, in case someone has experienced a similar issue and can give me a head's on the issue.

    My Tiles file is as follows:
    <tiles-definitions>
    <definition name="home" template="/jsp/home.jsp">
    <put-attribute name="title" value="Hello World"/>
    <put-attribute name="header" value="/jsp/tiles/header.jsp"/>
    <put-attribute name="body" value="index.body"/>
    <put-attribute name="footer" value="/jsp/tiles/footer.jsp" />
    </definition>
    <definition name="index.body" template="/jsp/tiles/body.jsp">
    <put-attribute name="helloMessages" value="/jsp/tiles/messages.jsp" />
    <put-attribute name="helloTranslators" value="/jsp/tiles/translators.jsp" />
    <put-attribute name="translator" value="/jsp/tiles/translator.jsp" />
    </definition>
    </tiles-definitions>

    Now, the helloMessage tile ( messages.jsp ) which is part of index.body has the following AJAX call inside:
    <a id="deleteMessage_${hello.id}" href="deleteMessage?id=${hello.id}">Delete Message </a>
    <script type="text/javascript">
    Spring.addDecoration(new Spring.AjaxEventDecoration({
    elementId:"deleteMessage_${hello.id}",
    event:"onclick",
    params: {fragments:"index.body"}
    }));
    </script>
    The actual call to the controller URL is working upon the click on the link ( it is deleting a message and I can see it in the server logs) however the 'index.body' tile never refreshes automatically to reflect these changes ( I have to hit reload ) , isn't the: params: { fragments:"index.body"} suppose to re-render the index.body tile automatically once the AJAX call is performed ?

    On a similar note, I have this other AJAX call inside the helloTranslators tile ( translators.jsp ):
    <a id="showTranslator_${hello.id}" href="translator?id=${hello.id}">Translator Details </a>
    <script type="text/javascript">
    Spring.addDecoration(new Spring.AjaxEventDecoration({
    elementId:"showTranslator_${hello.id}",
    event:"onclick",
    params: {fragments:"helloTranslators"}
    }));
    Here again, the actual call to the controller is being perfromed, but it seems once the controller attempts to relinquish control over the 'translator' tile logical name ( which is nested as a put-attirbute value ) the following error is thrown :
    SEVERE: Servlet.service() for servlet helloworld threw exception
    java.lang.NullPointerException
    at org.springframework.js.ajax.tiles2.AjaxTilesView.f lattenAttributeMap(AjaxTilesView.java:116)
    at org.springframework.js.ajax.tiles2.AjaxTilesView.r enderMergedOutputModel(AjaxTilesView.java:91)
    at org.springframework.web.servlet.view.AbstractView. render(AbstractView.java:252)
    at org.springframework.web.servlet.DispatcherServlet. render(DispatcherServlet.java:1173)
    at org.springframework.web.servlet.DispatcherServlet. doDispatch(DispatcherServlet.java:901)
    at org.springframework.web.servlet.DispatcherServlet. doService(DispatcherServlet.java:809)
    at org.springframework.web.servlet.FrameworkServlet.p rocessRequest(FrameworkServlet.java:571)
    at org.springframework.web.servlet.FrameworkServlet.d oGet(FrameworkServlet.java:501)
    at javax.servlet.http.HttpServlet.service(HttpServlet .java:690)
    at javax.servlet.http.HttpServlet.service(HttpServlet .java:803)
    at org.apache.catalina.core.ApplicationFilterChain.in ternalDoFilter(ApplicationFilterChain.java:269)
    at org.apache.catalina.core.ApplicationFilterChain.do Filter(ApplicationFilterChain.java:188)
    at org.apache.catalina.core.StandardWrapperValve.invo ke(StandardWrapperValve.java:213)
    at org.apache.catalina.core.StandardContextValve.invo ke(StandardContextValve.java:174)
    at org.apache.catalina.core.StandardHostValve.invoke( StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke (ErrorReportValve.java:117)
    at org.apache.catalina.core.StandardEngineValve.invok e(StandardEngineValve.java:108)
    at org.apache.catalina.connector.CoyoteAdapter.servic e(CoyoteAdapter.java:174)
    at org.apache.coyote.http11.Http11Processor.process(H ttp11Processor.java:874)
    at org.apache.coyote.http11.Http11BaseProtocol$Http11 ConnectionHandler.processConnection(Http11BaseProt ocol.java:665)
    at org.apache.tomcat.util.net.PoolTcpEndpoint.process Socket(PoolTcpEndpoint.java:528)
    at org.apache.tomcat.util.net.LeaderFollowerWorkerThr ead.runIt(LeaderFollowerWorkerThread.java:81)
    at org.apache.tomcat.util.threads.ThreadPool$ControlR unnable.run(ThreadPool.java:689)
    at java.lang.Thread.run(Thread.java:595)

    BTW, the -servlet.xml file contains the following resolvers:
    <bean id="tilesConfigurer"
    class="org.springframework.web.servlet.view.tiles2 .TilesConfigurer">
    <property name="definitions">
    <list>
    <value>/WEB-INF/tiles.xml</value>
    </list>
    </property>
    </bean>

    <bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedVie wResolver">
    <property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAj axTilesView"></property>
    </bean>

    Any ideas ? Per the docs, I understood the AjaxUrlBasedViewResolver made logical tile names out of every attribute name...similarly as I understood in the docs, the params: value in Spring.AjaxEventDecoration is there to refresh a tile by that name.....but I can't seem to either to work.

    Thanks in advance for any guidance or help on the issue.

  • #2
    Originally posted by drubio View Post
    The actual call to the controller URL is working upon the click on the link ( it is deleting a message and I can see it in the server logs) however the 'index.body' tile never refreshes automatically to reflect these changes ( I have to hit reload ) , isn't the: params: { fragments:"index.body"} suppose to re-render the index.body tile automatically once the AJAX call is performed ?
    Yes, but you need to use attribute names, not definition names. So in this case, it looks like you just want
    Code:
        params: { fragments:"body"}
    If you still have trouble after that change, I would suggest using Firebug to inspect the contents of the Ajax response to ensure they are what you expect. The other key point to remember is that the response handling works by replacement of existing DOM elements, so even if you are completely changing the content, there has to be some common containing element with a matching id.

    Also, make sure you are using 2.0.1 as there was a fix in there related to properly handling the nested definitions.

    Comment


    • #3
      Jeremy,

      Thanks for the tip...I got one scenario working thank's to your response and suggestion to use Firebug, but the way you mention triggered a bug ( may be a feature! )...

      Turns out the AJAX call's are nested inside the 'helloMessages' tile, using params: { fragments:"index.body"} in the call didn't do anything, then I tried with your suggestion { fragments:"body"} and seem's the 'body' tile is out of scope since its in the parent template...( got the following error )...
      -------------------------------
      No tiles attribute with a name of 'body' could be found for the current view: org.springframework.webflow.mvc.view.FlowAjaxTiles View: name 'home'; URL [home]
      at org.springframework.js.ajax.tiles2.AjaxTilesView.r enderMergedOutputModel(AjaxTilesView.java:98)
      at org.springframework.web.servlet.view.AbstractView. render(AbstractView.java:252)
      --------------------------------
      I any event, I used { fragment:"helloMessages,helloTranslators"} and now its refreshing these two internal tiles perfectly.

      However, on the other AJAX call I mention in this post I am still getting an error, the issue here seem's that the AJAXTilesView NEED'S a top level level tile by the same name as the default controller method.....
      The AJAX call that's working calls a method named 'delete' on the controller, but this method returns a "redirect:home", and given the Tiles file has a top level logical named 'home' no hiccups occur.
      The AJAX call that has issues is like this:

      <a id="showTranslator_${hello.id}" href="translator?id=${hello.id}">Translator Details </a>
      <script type="text/javascript">
      Spring.addDecoration(new Spring.AjaxEventDecoration({
      elementId:"showTranslator_${hello.id}",
      event:"onclick",
      params: {fragments:"translator"}
      }));
      In this case, the controller method named 'translator' returns a data set...but its expecting to find a tile by the name 'translator' , which I thought would be picked up with the nested "put-attribute name="translator"" thanks to the AJAXTileView making the attributes Tile name's...but it doesn't seem to enable them as such, I get the following error:
      org.springframework.js.ajax.tiles2.AjaxTilesView.f lattenAttributeMap(AjaxTilesView.java:116)

      org.springframework.js.ajax.tiles2.AjaxTilesView.r enderMergedOutputModel(AjaxTilesView.java:91)

      org.springframework.web.servlet.view.AbstractView. render(AbstractView.java:252)

      org.springframework.web.servlet.DispatcherServlet. render(DispatcherServlet.java:1173)

      org.springframework.web.servlet.DispatcherServlet. doDispatch(DispatcherServlet.java:901)

      org.springframework.web.servlet.DispatcherServlet. doService(DispatcherServlet.java:809)

      org.springframework.web.servlet.FrameworkServlet.p rocessRequest(FrameworkServlet.java:571)

      org.springframework.web.servlet.FrameworkServlet.d oGet(FrameworkServlet.java:501)


      I effectively made a top level tile named 'translator' and the AJAX call works...but it seems a Controller method can't hand off control to a tile if its nested as an attribute name....Is this by design ? Or am I missing something ?

      Thanks again for any input on the issue

      Comment


      • #4
        Got everything working, here are the workarounds/issues in case someone faces the same.

        On the error:
        No tiles attribute with a name of 'body' could be found for the current view: org.springframework.webflow.mvc.view.FlowAjaxTiles View: name 'home'; URL [home]
        at org.springframework.js.ajax.tiles2.AjaxTilesView.r enderMergedOutputModel(AjaxTilesView.java:98)
        at org.springframework.web.servlet.view.AbstractView. render(AbstractView.java:252)

        The reason top level name weren't being detected was the lack of the TilesView resolver, both the TilesView and FlowAjaxTilesView need to be declared to top level names to be recognized.

        <bean id="viewResolver"
        class="org.springframework.web.servlet.view.UrlBas edViewResolver">
        <property name="viewClass"><value>org.springframework.web.se rvlet.view.tiles2.TilesView</value></property>
        </bean>

        <bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedVie wResolver">
        <property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAj axTilesView"></property>
        </bean>


        On the second error:
        org.springframework.js.ajax.tiles2.AjaxTilesView.f lattenAttributeMap(AjaxTilesView.java:116)

        org.springframework.js.ajax.tiles2.AjaxTilesView.r enderMergedOutputModel(AjaxTilesView.java:91)

        org.springframework.web.servlet.view.AbstractView. render(AbstractView.java:252)

        org.springframework.web.servlet.DispatcherServlet. render(DispatcherServlet.java:1173)

        I got it to work modifying my Controller 'translator' method to return control to the top level 'home' tile, and placed the data through the model.addAttribute in the controller, this way it never needs to locate a tile by the same name as the method name....

        Basically, if the controller method is used for AJAX requests, it seems it always needs to return control the parent tile, and in case it needs to return data in the request it has to do so using ModelMap and model.addAttribute.


        Thanks again Jeremy for the initial tip !

        Comment


        • #5
          Hi drubio,

          I'm struggling with the same problem:
          could you please clarify a bit what you exactly meant by "it always needs to return control the parent tile"?

          Thanks,
          Chris

          Comment


          • #6
            Never mind. It was a bug: http://jira.springframework.org/browse/SWF-918

            Comment

            Working...
            X