Uploaded image for project: 'Tapestry 5'
  1. Tapestry 5
  2. TAP5-1984

Adding alerts doesn't work during ajax rendering

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 5.4
    • Component/s: tapestry-core
    • Labels:
      None

      Description

      When AlertManager.alert is used during the rendering (such as from setupRender) of an ajax request, where the Alerts component is not rendered in the ajax request, the alert doesn't get shown on that request but on the next one (respectively when the Alerts component is rendered the next time).

      The use case where this problem was found is when components that render inside a progressive display try to add alerts during rendering. A workaround is to catch the progressive display's event, and then delegate it to the embedded progressively-displayed component which wants to add the alert, so that it can add the alert before rendering. Another option is to completely decorate the AlertManager service with the fixed version below

      The bug can easily be reproduced by including the following component inside an ajax-rendered zone (with the Alerts component outside of the zone):

      public class AlertManagerAjaxRenderBugComponent
      {
      @Inject
      private Request request;

      @Inject
      private AlertManager alertManager;

      @SetupRender
      void setupRender()
      {
      if (request.isXHR())

      { // will not show up on this request, but only when Alerts is rendered the next time alertManager.alert(Duration.SINGLE, Severity.ERROR, "Hello"); }

      }
      }

      The reason is that in AlertManagerImpl the alerts are added with ajaxResponseRenderer.addCallback, which doesn't work when rendering has already begun. The proposed solution is to use the ajaxResponseRenderer before rendering, and the JavaScriptSupport from the environment during rendering.

      The following change to the AlertManagerImpl fixes this problem:

      private void addCallbackForAlert(final Alert alert)
      {
      JavaScriptCallback callback = new JavaScriptCallback()
      {
      public void run(JavaScriptSupport javascriptSupport)

      { javascriptSupport.addInitializerCall("addAlert", alert.toJSON()); }

      };

      // In order to support the creation of alerts both before and during rendering,
      // run the callback against the appropriate service
      final JavaScriptSupport javaScriptSupport = environment.peek(JavaScriptSupport.class);
      if (javaScriptSupport != null)

      { callback.run(javaScriptSupport); }

      else

      { ajaxResponseRenderer.addCallback(callback); }

      addAlertStorageCleanupCallback();
      }

      A similar problem exists for the cleanup of the alerts, which is not executed under these circumstances for the same reason. Use of the perThreadManager.addThreadCleanupListener instead fixes this problem.

      The attached patch contains both these fixes.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                hlship Howard M. Lewis Ship
                Reporter:
                cstichlberger Christoph Stichlberger
              • Votes:
                0 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: