Tapestry 5
  1. Tapestry 5
  2. TAP5-1

Clicking on a link that updates a zone before the page has fully loaded will result in a full page update and, often, a server-side exception

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 5.0.15
    • Fix Version/s: 5.0.16
    • Component/s: None
    • Labels:
      None

      Description

      I have a page with 2 ActionLinks - the first link updates the whole page; the second link specifies a zone.

      If you click on the two links in quick succession then an exception is thrown. Alternatively, just Reload the page and click on the second link before the page has finished reloading and you'll get the same exception.

      Here's the page, with source: http://202.177.217.122:8080/jumpstart/examples/javascript/ajax

      Here's the exception:

      A component event handler method returned the value org.apache.tapestry5.internal.structure.BlockImpl@80937b. Return type org.apache.tapestry5.internal.structure.BlockImpl can not be handled. Configured return types are java.lang.Class, java.lang.String, java.net.URL, org.apache.tapestry5.Link, org.apache.tapestry5.StreamResponse, org.apache.tapestry5.runtime.Component.

      I understand that Tapestry doesn't hook up zones etc. until the DOM is loaded. It's also been suggested to "check Request#isXhr in your event handler to see if it's an AJAX request - if it's not you can't return a Block, so you'll have to figure out another way to do what needs to be done."

      However, since this symptom will afflict every AJAX ActionLink out-of-the-box, it would be nice if the framework handled it so we don't have to code around it.

      Geoff

        Activity

        Hide
        Inge Solvoll added a comment -

        I tried someting now. Actually, if you just add the following in the link:

        onclick= function()

        {return false;}

        the link just does not respond to clicks before it has been zone-initialized by tapestry. Apparently, the zone-init replaces this onclick function, and voila, I avoid the ugly crash.

        Better than crashing, IMO.

        Show
        Inge Solvoll added a comment - I tried someting now. Actually, if you just add the following in the link: onclick= function() {return false;} the link just does not respond to clicks before it has been zone-initialized by tapestry. Apparently, the zone-init replaces this onclick function, and voila, I avoid the ugly crash. Better than crashing, IMO.
        Hide
        Inge Solvoll added a comment -

        The big question is: what global event should trigger the javascript that disables the links? It sure can't be dom:loaded together with zone-init, which would leave the situation pretty much unchanged

        Maybe inline javascript (this.onclick = function()

        {return false}

        ) generated server side based on information from the request?

        Show
        Inge Solvoll added a comment - The big question is: what global event should trigger the javascript that disables the links? It sure can't be dom:loaded together with zone-init, which would leave the situation pretty much unchanged Maybe inline javascript (this.onclick = function() {return false} ) generated server side based on information from the request?
        Hide
        Thiago H. de Paula Figueiredo added a comment -

        Inge said: "After all, in most cases the links will display right away anyway and the user won't notice that they were gone."

        Just to make my opinion clear, I'm not suggesting that the links should be hidden, just disable them (when they're clicked, they do nothing, but still appear in the page).

        Show
        Thiago H. de Paula Figueiredo added a comment - Inge said: "After all, in most cases the links will display right away anyway and the user won't notice that they were gone." Just to make my opinion clear, I'm not suggesting that the links should be hidden, just disable them (when they're clicked, they do nothing, but still appear in the page).
        Hide
        Inge Solvoll added a comment -

        I agree with Thiago, graceful degradation is important and I would like to keep the link in the href.

        If you have many links on the page that needs zone init, it is very likely that the user will click one of them before init is complete. Of course, if I was serious about graceful degradation, I should have already provided a non-XHR fallback and I wouldn't be barking up the T5-tree

        Having said that, I would like an elegant solution to enable my XHR-enabled clients to avoid this problem. A javascript event telling me that tapestry init has finished would be helpful. Thiagos suggestion in the previous post, disabling/hiding links with javascript, is probably a good default behaviour. After all, in most cases the links will display right away anyway and the user won't notice that they were gone.

        Show
        Inge Solvoll added a comment - I agree with Thiago, graceful degradation is important and I would like to keep the link in the href. If you have many links on the page that needs zone init, it is very likely that the user will click one of them before init is complete. Of course, if I was serious about graceful degradation, I should have already provided a non-XHR fallback and I wouldn't be barking up the T5-tree Having said that, I would like an elegant solution to enable my XHR-enabled clients to avoid this problem. A javascript event telling me that tapestry init has finished would be helpful. Thiagos suggestion in the previous post, disabling/hiding links with javascript, is probably a good default behaviour. After all, in most cases the links will display right away anyway and the user won't notice that they were gone.
        Hide
        Thiago H. de Paula Figueiredo added a comment -

        I would really like this href="#" behaviour to be rolled back, because it completely prevents the graceful degradation of AJAX links. One other possible solution would be to generate links as before, but use JavaScript to disable them. When the DOM is fully loaded, reenable the links through JavaScript.

        Show
        Thiago H. de Paula Figueiredo added a comment - I would really like this href="#" behaviour to be rolled back, because it completely prevents the graceful degradation of AJAX links. One other possible solution would be to generate links as before, but use JavaScript to disable them. When the DOM is fully loaded, reenable the links through JavaScript.
        Hide
        Howard M. Lewis Ship added a comment -

        I'm modifying the components to write out a href attribute as "#" (or action="#" for Form) and put the true URL in the JavaScript. This means the link will do nothing (possibly a page refresh, depending on browser) until the JavaScript links in. This leaves, as a question, how to handle graceful degradation from Ajax to traditional (page oriented) behavior ... which was the intent of leaving the href unchanged even when zone parameter was bound.

        Show
        Howard M. Lewis Ship added a comment - I'm modifying the components to write out a href attribute as "#" (or action="#" for Form) and put the true URL in the JavaScript. This means the link will do nothing (possibly a page refresh, depending on browser) until the JavaScript links in. This leaves, as a question, how to handle graceful degradation from Ajax to traditional (page oriented) behavior ... which was the intent of leaving the href unchanged even when zone parameter was bound.
        Hide
        Geoff Callender added a comment -

        Indeed, that's what I ended up doing in that page.

        Show
        Geoff Callender added a comment - Indeed, that's what I ended up doing in that page.
        Hide
        Howard M. Lewis Ship added a comment -

        Further, your code can inject the Request object and check its .isXHR() method to determine what to return: probably this (the current page object) for a non-Ajax request.

        Show
        Howard M. Lewis Ship added a comment - Further, your code can inject the Request object and check its .isXHR() method to determine what to return: probably this (the current page object) for a non-Ajax request.
        Hide
        Howard M. Lewis Ship added a comment -

        I can't help but wonder if this is not a wide problem than just Tapestry; any application that uses Prototype and defers (as is strongly suggested) linking event handlers until the dom:loaded event may be subject to this.

        What would be necessary to fully address this would be to use different actions for traditional requests vs. Ajax requests, so that a traditional request can be identified in the Ajax pipeline and ... what? Ignored? That wouldn't work either, you'd see a blank page after clicking what looked like an Ajax link.

        Show
        Howard M. Lewis Ship added a comment - I can't help but wonder if this is not a wide problem than just Tapestry; any application that uses Prototype and defers (as is strongly suggested) linking event handlers until the dom:loaded event may be subject to this. What would be necessary to fully address this would be to use different actions for traditional requests vs. Ajax requests, so that a traditional request can be identified in the Ajax pipeline and ... what? Ignored? That wouldn't work either, you'd see a blank page after clicking what looked like an Ajax link.

          People

          • Assignee:
            Howard M. Lewis Ship
            Reporter:
            Geoff Callender
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development