5 Replies Latest reply on Sep 8, 2008 12:19 PM by achildress

    prevent modal panel close on ajax error

    achildress

      I have a simple modal panel on which the user enters data, and presses a Save button (a4j:commandButton) to save the data. If validation errors occur, I can trap them and prevent the modal panel from closing, but if some other error occurs and I throw an AbortProcessingException from the backing bean code to indicate that there was something wrong during the ajax call, the modal panel goes ahead and closes. Is there an elegant way (or even inelegant, as I am willing to make it ugly if necessary) to prevent the modal panel from closing and pass back an error message to be displayed by the rich:messages tag? I have tried in the past to add an error to the Faces context by using FacesContext.getCurrentInstance().addMessage during processing that occurs after validation, but I never seem to be able to push that message back to the browser.

      Has anybody tackled this before, and if so, what was your solution?

        • 1. Re: prevent modal panel close on ajax error
          ilya_shaikovsky

          seems facesContext.getCurrentInstance.addMessage - is appropriate way.. May be lets try to dig why it isn't works?

          • 2. Re: prevent modal panel close on ajax error
            achildress

            Ilya, is the assumption that you can do FacesContext.getCurrentInstance().addMessage anywhere in the JSF lifecycle on the server (even outside the validation phase), and any error message you place in the context will be shown on the client side? If so, then yes, I think that there might be a bug somewhere, as the error message doesn't seem to be returned, and therefore the modal panel closes as if nothing went wrong. What do we need to do to investigate this?

            • 3. Re: prevent modal panel close on ajax error
              ilya_shaikovsky

              lets start from your code snippets ;)

              • 4. Re: prevent modal panel close on ajax error
                achildress

                The scenario I am trying to handle is when the data passes validation successfully, but there is a database error that occurs when trying to update data, so I want the client to see the error and be able to press the Save button again to try to save the data again. This is a very common application paradigm and I'm sure that somebody somewhere has found an elegant way to handle it. I just have not stumbled upon it myself.

                • 5. Re: prevent modal panel close on ajax error
                  achildress

                  Here's the modal panel facelet code:

                  <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                   xmlns:ui="http://java.sun.com/jsf/facelets"
                   xmlns:h="http://java.sun.com/jsf/html"
                   xmlns:f="http://java.sun.com/jsf/core"
                   xmlns:a4j="http://richfaces.org/a4j"
                   xmlns:rich="http://richfaces.org/rich">
                   <a4j:form id="ssnform" binding="#{SSNBean.myform}">
                   <h:inputHidden id="requiredEdit" formName="ssnform" normalStyleClass="stdTextBox" errorStyleClass="stdTextBoxError" warnStyleClass="stdTextBoxWarn" value="abc">
                   <f:validator validatorId="requiredValidator" />
                   </h:inputHidden>
                   <a4j:outputPanel ajaxRendered="true" id="offenderssn">
                   <table width="100%" align="center">
                   <tr>
                   <td align="right">
                   <h:outputText id="ssnLabel" value="SSN:" styleClass="stdLabel" />
                   </td>
                   <td align="left">
                   <h:inputText onkeypress="return event.keyCode!=13" myRequired="true" myLabel="ssnLabel" id="ssn" label="SSN" value="#{SSNBean.otherIdentifier.otherIdentifier}" maxlength="9" size="14" styleClass="stdTextBox" normalStyleClass="stdLabel" errorStyleClass="stdLabelError" warnStyleClass="stdLabelWarn">
                   <f:validator validatorId="ssnValidator" />
                   </h:inputText>
                   </td>
                   </tr>
                   </table>
                   <center>
                   <table>
                   <tr>
                   <td>
                   <a4j:commandButton value="Save" limitToList="true" actionListener="#{DOPIntakeAdminTechInterviewBean.saveSSN}" oncomplete="ssnwindowclose();" reRender="offenderssn, ssnerrors, offenderssnlist"/>
                   <rich:spacer width="14px"></rich:spacer>
                   <a4j:commandButton value="Cancel" immediate="true" limitToList="true" action="#{SSNBean.resetForm}" oncomplete="ssnwindowclose();" reRender="ssnerrors"/>
                   </td>
                   </tr>
                   </table>
                   </center>
                   <center>
                   <table>
                   <tr>
                   <td>
                   <a4j:outputPanel id="ssnerrors">
                   <h:inputHidden id="maximumSeverity" rendered="#{! empty facesContext.maximumSeverity}" value="#{facesContext.maximumSeverity.ordinal}" />
                   <rich:messages globalOnly="true" id="ssnerror" layout="list" styleClass="stdLabel">
                   <f:facet name="errorMarker">
                   <h:graphicImage value="/images/failed.gif" />
                   </f:facet>
                   </rich:messages>
                   </a4j:outputPanel>
                   </td>
                   </tr>
                   </table>
                   </center>
                   </a4j:outputPanel>
                   </a4j:form>
                   <script>
                   function ssnwindowclose(){
                   if (myajaxerror) {
                   myajaxerror = false;
                   else if (document.all('mpsource:ssnform:maximumSeverity')==null) {
                   Richfaces.hideModalPanel('genericmp');
                   }
                  
                   }
                   function offenderssnmpShowComplete() {
                   window.setTimeout(
                   function() {
                   document.all('mpsource:ssnform:ssn').focus();
                   document.all('mpsource:ssnform:ssn').select();
                   }, 100);
                   }
                   </script>
                  </ui:composition>
                  



                  The backing bean saveSSN method:

                   public void saveSSN(ActionEvent event) {
                   OtherIdentifierBean anOtherIdentifierBean =
                   (OtherIdentifierBean)FacesContext.getCurrentInstance().getExternalContext()
                   .getSessionMap().get("SSNBean");
                   OtherIdentifierBean anOtherIdentifierBean =
                   (OtherIdentifierBean)FacesContext.getCurrentInstance().getExternalContext()
                   .getSessionMap().get("SSNBean");
                   OffenderBean aSelectedOffenderBean =
                   (OffenderBean)FacesContext.getCurrentInstance().getExternalContext()
                   .getSessionMap().get("IntakeOffenderBean");
                   OffenderIdentificationService oi =
                   ServiceFactory.getServiceFactory(FactoryType.REMOTE)
                   .getOffenderIdentificationService();
                   try {
                   oi.createSocialSecurityNumber(anOtherIdentifierBean.getOtherIdentifier());
                   }
                   catch (ValidationException e) {
                   FacesContext.getCurrentInstance().addMessage(null,new FacesMessage(FacesMessage.SEVERITY_ERROR, "ssn: " + "problem happened", "ssn: " + "problem happened"));
                   throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_INFO, "xxx", "xxx"));
                  // throw new AbortProcessingException(e);
                   }
                   aSelectedOffenderBean.clearSSNS();
                   FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("IntakeOffenderBean", aSelectedOffenderBean);
                   FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put("SSNBean", null);
                   }
                  


                  Try to ignore the fact that the database service being called throws an exception called ValidationException. It is misnamed if you ask me, but I'm not the service writer here. Basically I have tried:

                  1- to throw an AbortProcessingException, which terminates the ajax call, and obviously sends no feedback to the client to let it know not to close the modal panel
                  2- to do a FacesContext.getCurrentInstance().addMessage and then throw a subsequent AbortProcessingException, which also sends no feedback to the client to let it know not to close the modal panel
                  3- to do a FacesContext.getCurrentInstance().addMessage and then throw a subsequent ValidatorException, which again sends no feedback to the client to let it know not to close the modal panel

                  Obviously some combination of these should work, but I have no clue what.

                  Thanks for taking a look and let me know if you need further code snippets.