Announcement Announcement Module
Collapse
No announcement yet.
RichFaces modal dialog support Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • RichFaces modal dialog support

    I just want to share my experience of RichFaces modal dialog support without using Spring JS. Steps to introduce such support into your program (with facelets):

    1) Request for popup from server:

    RichFacesDialogAjaxHandler.java:
    Code:
    public class RichFacesDialogAjaxHandler extends RichFacesAjaxHandler
    {
      private static final Logger log = Logger.getLogger(RichFacesDialogAjaxHandler.class);
    
      @Override
      public void sendAjaxRedirect
         (String targetUrl, HttpServletRequest request, HttpServletResponse response, boolean popup)
         throws IOException
      {
        if( popup && isRichFacesAjaxRequest(request, response) )
        {
          log.debug("Sending dialog request: " + targetUrl);
    
          response.setHeader("RichFaces-Modal-View", "true");
          response.setHeader("RichFaces-Redirect-URL", response.encodeRedirectURL(targetUrl));
    
          return;
        }
    
        super.sendAjaxRedirect(targetUrl, request, response, popup);
      }
    }
    2) Processing request on client:

    dialog.js:
    Code:
    var ModalDialogSupport = {};
    
    ModalDialogSupport.originalProcessResponse = A4J.AJAX.processResponse;
    
    A4J.AJAX.processResponse = function(req)
    {
      try
      {
        if( req.getResponseHeader("RichFaces-Modal-View") == "true" )
        {
          var url = req.getResponseHeader("RichFaces-Redirect-URL");
    
          LOG.debug("Request for modal dialog: " + url);
    
          var oncomplete = function(request, domEvt, data)
          {
            LOG.debug("Request for modal dialog is completed");
    
            for( var i = 0; i < ModalPanel.panels.length; i++ )
            {
              var pnl = ModalPanel.panels[i];
              if( pnl && pnl.markerId )
              {
                LOG.debug("Dialog id: " + pnl.markerId.id);
              }
            }
    
            LOG.debug("Last dialog id: " + ModalDialogSupport.lastDialogId);
    
            Richfaces.showModalPanel( ModalDialogSupport.lastDialogId );
          };
    
          A4J.AJAX.Submit
          ("_viewRoot", "modalPanel_region_form", null,
             {
               "actionUrl": url,
               "oncomplete": oncomplete
             }
          );
    
          return;
        }
    
        ModalDialogSupport.originalProcessResponse(req);
      }
      catch( e )
      {
        LOG.error("Error in processResponse: " + e.message);
      }
    };
    
    ModalDialogSupport.lastDialogId = undefined;
    
    ModalDialogSupport.registerDialog = function(dialogId)
    {
      ModalDialogSupport.lastDialogId = dialogId;
    };
    3) Support for dialogs on pages:

    modalDialogSupport.xhtml:
    HTML Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <ui:composition
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:c="http://java.sun.com/jstl/core"
       xmlns:ui="http://java.sun.com/jsf/facelets"
       xmlns:a4j="http://richfaces.org/a4j">
    
      <!--@elvariable id="modalLevel" type="java.lang.Integer"-->
    
      <c:set var="modalPanelRegionId" value="modalPanel#{modalLevel}_region"/>
    
      <c:if test="#{modalLevel==null}">
        <a4j:loadScript src="/scripts/dialog.js"/>
    
        <h:form id="modalPanel_region_form"/>
      </c:if>
    
    
      <a4j:outputPanel id="#{modalPanelRegionId}"/>
    </ui:composition>
    modalDialogTemplate.xhtml:
    HTML Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <ui:composition
       xmlns="http://www.w3.org/1999/xhtml"
       xmlns:f="http://java.sun.com/jsf/core"
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:c="http://java.sun.com/jstl/core"
       xmlns:ui="http://java.sun.com/jsf/facelets"
       xmlns:a4j="http://richfaces.org/a4j"
       xmlns:rich="http://richfaces.org/rich">
    
      <!--@elvariable id="modalPanelTitle" type="java.lang.String"-->
      <!--@elvariable id="modalLevel" type="java.lang.Integer"-->
    
      <c:set var="modalPanelId" value="modalPanel#{modalLevel}"/>
    
      <a4j:outputPanel id="#{modalPanelId}_region" ajaxRendered="true">
        <script type="text/javascript">
          ModalDialogSupport.registerDialog('#{modalPanelId}');
        </script>
    
        <rich:modalPanel id="#{modalPanelId}" autosized="true" showWhenRendered="false">
    
          <f:facet name="header">
            <h:outputText value="#{modalPanelTitle}"/>
          </f:facet>
    
          <f:facet name="controls">
            <h:graphicImage
               value="/images/closePanel.png"
               style="cursor:pointer"
               alt="Close"
               onclick="#{modalPanelId}_cancelDialog();"/>
          </f:facet>
    
          <rich:hotKey
             key="esc"
             handler="#{modalPanelId}_cancelDialog();"/>
    
          <h:form id="#{modalPanelId}_form">
            <a4j:jsFunction
               name="#{modalPanelId}_cancelDialog"
               immediate="true"
               action="cancel"
               onbeforedomupdate="Richfaces.hideModalPanel('#{modalPanelId}');"
               />
          </h:form>
    
          <ui:insert name="modalPanelContent"/>
        </rich:modalPanel>
    
        <!-- Nesting dialog support -->
        <ui:include src="/WEB-INF/dialogs/modalDialogSupport.xhtml">
          <ui:param name="modalLevel" value="#{modalLevel+1}"/>
        </ui:include>
    
      </a4j:outputPanel>
    
    </ui:composition>
    4) Usage:

    confirmDialog.xhtml:
    HTML Code:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <ui:composition
       xmlns:f="http://java.sun.com/jsf/core"
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:c="http://java.sun.com/jstl/core"
       xmlns:ui="http://java.sun.com/jsf/facelets"
       xmlns:a4j="http://richfaces.org/a4j"
       xmlns:rich="http://richfaces.org/rich"
       template="/WEB-INF/dialogs/modalDialogTemplate.xhtml">
    
      <ui:define name="modalPanelContent">
        <table>
          <tr>
            <td align="center">
              <h:outputText value="Are you sure?"/>
            </td>
          </tr>
          <tr>
            <td align="center">
              <h:form id="toolbarForm">
                <table cellspacing="10">
                  <tr>
                    <td>
                      <a4j:commandButton id="okButton" styleClass="rich-button"
                                         value="OK" immediate="true" action="ok"/>
                    </td>
                    <td>
                      <a4j:commandButton id="cancelButton" styleClass="rich-button"
                                         value="Cancel" immediate="true" action="cancel"/>
                    </td>
                  </tr>
                </table>
              </h:form>
            </td>
          </tr>
        </table>
      </ui:define>
    
    </ui:composition>
    main_template.xhtml (somewhere in the page):
    HTML Code:
    <ui:include src="/WEB-INF/dialogs/modalDialogSupport.xhtml"/>
    flow.xml:
    HTML Code:
      <view-state id="confirmState" view="confirmDialog.xhtml" popup="true">
        <transition on="ok" to="confirmState2"/>
        <transition on="cancel" to="processCancelled" />
      </view-state>
    
      <view-state id="confirmState2" view="confirmDialog.xhtml" popup="true">
        <on-entry>
          <set name="viewScope.modalLevel" value="1" type="int"/>
        </on-entry>
    
        <transition on="ok" to="nextStage"/>
        <transition on="cancel" to="confirmState" />
      </view-state>
    Last edited by Hedin; Jan 25th, 2009, 10:47 AM.

  • #2
    Awesome

    Great post,
    thanks a lot

    Comment


    • #3
      RequestContext

      Hi,

      Do you know how I can get the RequestContext object in the AjaxHandler.

      My problem :
      I put attributes in the ViewScope, but when in the method
      Code:
      public void sendAjaxRedirect  ( String targetUrl, HttpServletRequest request, HttpServletResponse response, boolean popup )
      none of my attributes are inside the request.

      The request is merged with the ViewScope after the Ajax Handler call.

      .--
      Julien.

      Comment


      • #4
        Originally posted by jujuz View Post
        Do you know how I can get the RequestContext object in the AjaxHandler.
        Did you try RequestContextHolder.getRequestContext()?

        Comment


        • #5
          yes, NullPointerException ....

          Comment


          • #6
            Originally posted by jujuz View Post
            yes, NullPointerException ....
            Well, looks like RequestContext isn't alive at that point. You can try to pass parameters from flow by setting data in HttpServletRequest throught use requestParameters or externalContext variables:

            HTML Code:
            <set name="requestParameters.ajaxParam" value="'paramValue'"/>
            
            <set name="externalContext.requestMap.ajaxParam" value="'paramValue'"/>

            Comment


            • #7
              Code:
                      <set name="externalContext.requestMap.test1" value="'paramValue1'">
              Does not works, Request are not update at this moment.

              AND :

              Code:
                      <set name="requestParameters.test2" value="'paramValue2"/>
              throw :
              Code:
              Caused by: java.lang.UnsupportedOperationException: Cannot mutate immutable attribute collections; operation disallowed
              	at org.springframework.webflow.expression.WebFlowOgnlExpressionParser$MapAdaptablePropertyAccessor.setProperty(WebFlowOgnlExpressionParser.java:64)
              	at ognl.OgnlRuntime.setProperty(OgnlRuntime.java:1670)
              	at ognl.ASTProperty.setValueBody(ASTProperty.java:101)
              	at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:177)
              	at ognl.SimpleNode.setValue(SimpleNode.java:246)
              	at ognl.ASTChain.setValueBody(ASTChain.java:172)
              	at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:177)
              	at ognl.SimpleNode.setValue(SimpleNode.java:246)
              	at ognl.Ognl.setValue(Ognl.java:476)
              	at org.springframework.binding.expression.ognl.OgnlExpression.setValue(OgnlExpression.java:103)
              	at org.springframework.webflow.action.SetAction.doExecute(SetAction.java:76)
              	at org.springframework.webflow.action.AbstractAction.execute(AbstractAction.java:188)
              	at org.springframework.webflow.execution.AnnotatedAction.execute(AnnotatedAction.java:145)
              	at org.springframework.webflow.execution.ActionExecutor.execute(ActionExecutor.java:51)
              	... 77 more
              .
              In fact before you told me these solution I had already test it.

              RequestContextHOlder.getRequest() is the good solution, but it doesnt works,
              I have no more solution, I hope Keith will post a little reply with THE good solution
              JIRA or not JIRA ...
              Last edited by jujuz; Jan 30th, 2009, 03:39 AM.

              Comment


              • #8
                Originally posted by jujuz View Post
                I have no more solution...
                I would not give up so easily. :-)

                In ExternalContext there is exists more properties to try: sessionMap, globalSessionMap, applicationMap, nativeContext, nativeRequest...

                If none of them working, you are allways have possibilities to create your own parameters holder with little help of ThreadLocal (see implementation of RequestContextHolder).

                Comment


                • #9
                  Don't worry I will not give up,

                  [QUOTE ]
                  In ExternalContext there is exists more properties to try: sessionMap, globalSessionMap, applicationMap, nativeContext, nativeRequest...
                  [/QUOTE]
                  I have analyse in debug mode the ExternalContext flow. None of his properties are merge with the HttpRequest or HttpSession in the AjaxHandler method.

                  The merge are done after.


                  If none of them working, you are allways have possibilities to create your own parameters holder with little help of ThreadLocal (see implementation of RequestContextHolder).
                  I Agree, I will find a fake solution, but before I would prefer to be sure they re is not better solution (A Approuve Spring Solution)


                  ---> to be continued ...

                  Comment


                  • #10
                    It s a shame,

                    RequestContext in RequestContextHolder is set after AjaxHanler.sendAjaxRedirect

                    So I cant use this method.

                    Comment


                    • #11
                      I ask to Spring team

                      ...

                      Comment


                      • #12
                        This code is works for me:

                        HTML Code:
                         <view-state id="stateId"...>
                            <on-entry>
                              <set name="externalContext.requestMap.targetView" value="'_new'"/>
                            </on-entry>
                         </view-state>
                        Code:
                          @Override
                          public void sendAjaxRedirect
                             (String targetUrl, HttpServletRequest request, HttpServletResponse response, boolean popup)
                             throws IOException
                          {
                            log.debug("sendAjaxRedirect(targetUrl="+targetUrl+", popup="+popup+')');
                        
                            log.debug( "attribute targetView=" + request.getAttribute("targetView") );
                        Log output:

                        Code:
                        springframework.webflow.engine.ViewState - Entering state 'stateId' of flow...
                        springframework.webflow.execution.ActionExecutor - Executing [SetAction@c44470 name = externalContext.requestMap.targetView, value = '_new', type = [null]]
                        ...
                        springframework.webflow.mvc.servlet.FlowHandlerAdapter - Sending flow execution redirect to ...
                        ...AjaxHandler - sendAjaxRedirect(targetUrl=..., popup=false)
                        ...AjaxHandler - attribute targetView=_new

                        Comment


                        • #13
                          AWESOME !!! thanks a lot it works,

                          I am angry because I have not make the test on requestMap,

                          thanks for Help--- I had forgiven and waited for a JIRA reply ...

                          Comment


                          • #14
                            Hi Hedin,

                            I have tried your code but instead of the RichFaces popup dialog a Spring Faces popup dialog appears with an error message:

                            Component to be rendered with id 'j_id88:j_id94' could not be found.

                            I put the files in the following directory structure:

                            web/WEB-INF/dialogs/modalDialogSupport.xhtml
                            web/WEB-INF/dialogs/modalDialogTemplate.xhtml
                            web/scripts/dialog.js
                            web/WEB-INF/flows/main/confirmDialog.xhtml
                            web/WEB-INF/flows/main/main-flow.xml

                            And I replaced the ajaxHandler property in flowController bean with the RichFacesDialogAjaxHandler class.

                            I also tried to create a subflow with the same result.

                            If you don't know what I am doing wrong could you please upload a sample application?

                            Thanks,

                            paul

                            Comment


                            • #15
                              Originally posted by paulz View Post
                              Hi Hedin,

                              I have tried your code but instead of the RichFaces popup dialog a Spring Faces popup dialog appears with an error message:

                              Component to be rendered with id 'j_id88:j_id94' could not be found.
                              If Spring Faces popup dialog appears, then you must be using sf:commandButton component - in this case there is spring ajax request issued. For RichFaces ajax you must use a4j:commandButton instead.

                              Originally posted by paulz View Post
                              If you don't know what I am doing wrong could you please upload a sample application?
                              Don't have a time for this right now, sorry. May be later...

                              Comment

                              Working...
                              X