10 Replies Latest reply on Oct 17, 2008 1:07 PM by Coral Featherstone

    rich:modalPannel + validation + DataModelSelection

    Ivan Pullman Newbie

      Hi, I have rich:modalPannel from dataTable. I'm using DataModelSelection to open modalPannel and in modalPannel I want to edit sample input.


      If I have a validation error, I want cancel this form and select other item from table, but in modalPanel is previous item and I don't know, how to rerender this.


      My code:


      ProjectManager.java


      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Factory;
      import org.jboss.seam.annotations.Out;
      import org.jboss.seam.annotations.Scope;
      import org.jboss.seam.annotations.In;
      import org.jboss.seam.annotations.datamodel.DataModel;
      import org.jboss.seam.annotations.datamodel.DataModelSelection;
      import org.jboss.seam.ScopeType;
      
      import javax.ejb.Stateless;
      import javax.persistence.PersistenceContext;
      import javax.persistence.EntityManager;
      import java.util.List;
      
      import sk.bgs.controlling.entity.Project;
      import sk.bgs.controlling.entity.User;
      
      @Stateless
      @Name(value = "project")
      @Scope(value = ScopeType.PAGE)
      public class ProjectManager implements ProjectManagerLocal {
      
           @In
           private User thisUser;
      
           @DataModel
           private List<Project> projectList;
      
           @DataModelSelection
           @Out(required=false)
           private Project currentProject;
      
           private Boolean completed = Boolean.FALSE;
      
           @PersistenceContext
           private EntityManager em;
      
           public void setCompleted(Boolean completed) {
                this.completed = completed;
           }
      
           public Boolean isCompleted() {
                return completed;
           }
      
           @Factory("projectList")
           public void projectList() {
                projectList = em.createQuery("select x from Project x").getResultList();
                for (Project proj : projectList) {
                     if (thisUser.getMarkedProjects().contains(proj.getId())) {
                          proj.setMarked(Boolean.TRUE);
                     }
                }
           }
      
           public void createProject() {
                currentProject = new Project();
                currentProject.setCreator(thisUser.getId());
           }
      
           public void editProject() {
                if (currentProject.getId() != null) {
                     em.merge(currentProject);
                } else {
                     em.persist(currentProject);
                }
                projectList();
           }
      
           public void markProject() {
                if (currentProject.getMarked()) {
                     thisUser.getMarkedProjects().add(currentProject.getId());
                } else {
                     thisUser.getMarkedProjects().remove(currentProject.getId());
                }
      
                em.merge(thisUser);
           }
      
           public void fake() {
           }
      }



      list.xhtml



      <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <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:s="http://jboss.com/products/seam/taglib"
                                              xmlns:a="http://richfaces.org/a4j"
                                              xmlns:rich="http://richfaces.org/rich"
                                              template="template.xhtml">
      
           <ui:define name="page-title">Projects</ui:define>
           
           <ui:define name="content">
      
                <ui:include src="projectEdit.xhtml"/>
      
                <div class="section">
                     <h:form id="projectTable">
      
                          <a:commandButton value="Add project" action="#{project.createProject}" reRender="projectEdit"
                                               oncomplete="Richfaces.showModalPanel('projectPanel')"/>
                          <h:dataTable var="item" value="#{projectList}">
                               <h:column>
                                    <f:facet name="header">ISO code</f:facet>
                                    <h:outputText value="#{item.code}"/>
                               </h:column>
                               <h:column>
                                    <f:facet name="header">Name</f:facet>
                                    <a:commandLink action="#{project.fake}" oncomplete="Richfaces.showModalPanel('projectPanel')"
                                                      value="#{item.name}" reRender="projectEdit"/>
                               </h:column>
                               <h:column>
                                    <f:facet name="header">Customer</f:facet>
                                    <h:outputText value="#{item.customer}"/>
                               </h:column>
                               <h:column>
                                    <f:facet name="header">Created</f:facet>
                                    <h:outputText value="#{item.created}"/>
                               </h:column>
                               <h:column>
                                    <f:facet name="header">Stop date</f:facet>
                                    <h:outputText value="#{item.stop}"/>
                               </h:column>
                               <h:column>
                                    <f:facet name="header">Marked</f:facet>
                                    <h:selectBooleanCheckbox id="marked" value="#{item.marked}">
                                         <a:support event="onclick" action="#{project.markProject}"/>
                                    </h:selectBooleanCheckbox>
                               </h:column>
                          </h:dataTable>
                     </h:form>
                </div>
      
           </ui:define>
      
      </ui:composition>



      projectEdit.xhtml



      <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <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:s="http://jboss.com/products/seam/taglib"
                                              xmlns:a="http://richfaces.org/a4j"
                                              xmlns:rich="http://richfaces.org/rich">
      
           <a:outputPanel ajaxRendered="true">
                <h:form style="display:none" prependId="false">
                     <h:inputHidden id="maximumSeverity" value="#{facesContext.maximumSeverity.ordinal}"/>
                </h:form>
          </a:outputPanel>
      
           <script type="text/javascript">
                function ajaxRequestContainsErrors() {
                     return document.getElementById("maximumSeverity").value == "2";
                }
           </script>
      
           <rich:modalPanel id="projectPanel" autosized="true" width="820">
                <f:facet name="header">
                     <h:outputText value="Editacia projektu"/>
                </f:facet>
                <a:form id="projectEdit">
                     <fieldset>
                          <s:decorate id="codeDecorate" template="edit.xhtml">
                               <ui:define name="label">ISO code:</ui:define>
                               <h:inputText id="code" value="#{currentProject.code}" maxlength="24" size="30" required="true"/>
                          </s:decorate>
                          <s:decorate id="nameDecorate" template="edit.xhtml">
                               <ui:define name="label">Name:</ui:define>
                               <h:inputText id="name" value="#{currentProject.name}" maxlength="64" size="68"/>
                          </s:decorate>
                          <s:decorate id="customerDecorate" template="edit.xhtml">
                               <ui:define name="label">Customer:</ui:define>
                               <h:inputText id="customer" value="#{currentProject.customer}" maxlength="64" size="68"/>
                          </s:decorate>
                          <s:decorate id="startDecorate" template="edit.xhtml">
                               <ui:define name="label">Start date:</ui:define>
                               <rich:calendar firstWeekDay="1" value="#{currentProject.start}" id="startDate"
                                    datePattern="dd.MM.yyyy" locale="#{localeSelector.locale}"
                                    showApplyButton="false" showFooter="false" showWeeksBar="false" showWeekDaysBar="false"/>
                          </s:decorate>
                          <s:decorate id="stopDecorate" template="edit.xhtml">
                               <ui:define name="label">Stop date:</ui:define>
                               <rich:calendar firstWeekDay="1" value="#{currentProject.stop}" id="stopDate"
                                    datePattern="dd.MM.yyyy" locale="#{localeSelector.locale}"
                                    showApplyButton="false" showFooter="false" showWeeksBar="false" showWeekDaysBar="false"/>
                          </s:decorate>
                          <s:decorate id="estDecorate" template="edit.xhtml" rendered="#{s:hasRole('manager') || s:hasRole('sales')}">
                               <ui:define name="label">Estimation:</ui:define>
                               <h:inputText id="estimation" value="#{currentProject.estimation}" maxlength="8" size="12"/>
                          </s:decorate>
                          <s:decorate id="descDecorate" template="edit.xhtml">
                               <ui:define name="label">Description:</ui:define>
                               <h:inputText id="desc" value="#{currentProject.description}" maxlength="512" size="80"/>
                          </s:decorate>
                          <div class="buttonBox">
                               <s:button id="cancel" action="cancel" value="Storno">
                                    <rich:componentControl for="projectPanel" event="onclick" operation="hide"/>
                               </s:button>
                               &#160;
                               <a:commandButton id="submit" action="#{project.editProject}" reRender="projectEdit"
                                          oncomplete="if (!ajaxRequestContainsErrors()) Richfaces.hideModalPanel('projectPanel');" value="Submit"/>
                          </div>
                     </fieldset>
                </a:form>
           </rich:modalPanel>
      
      </ui:composition>



      edit.xhtml



      <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      <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:s="http://jboss.com/products/seam/taglib">
                       
          <div class="entry">
              <s:label styleClass="label #{invalid?'errors':''}">
                  <ui:insert name="label"/>
                  <s:span styleClass="required" rendered="#{required}">*</s:span>
              </s:label>
              <span class="input #{invalid?'errors':''}">
                  <s:validateAll>
                      <ui:insert/>
                  </s:validateAll>
              </span>
              <s:message styleClass="error errors"/>
          </div>
          
      </ui:composition>



      Can you help me? Thank's

        • 1. Re: rich:modalPannel + validation + DataModelSelection
          Vincent Crepin Newbie

          Hello. I have exactly the same problem. Have you found a solution to this one ?


          Thank you a lot.

          • 2. Re: rich:modalPannel + validation + DataModelSelection
            Damian Harvey Apprentice

            Put some logging in to check if the value of currentProject is being reset. You could always try putting an a4j:log/> on your page to see if ajx4jsf is performing a reRender (access it with CRTL-L).


            IMHO, you're far better to pass the value of currentProject in your EL than rely on @DataModelSelection.


            Try changing fake() to


            public void setProject(Project currentProject) {
                this.currentProject = currentProject;
            }
            


            and change your name column in your datatable to :


            <h:column>
               <f:facet name="header">Name</f:facet>
               <a:commandLink action="#{project.setProject(item)}"
                  oncomplete="Richfaces.showModalPanel('projectPanel')"
                  value="#{item.name}" 
                  reRender="projectEdit"/>
            </h:column>
            



            Also you can handle catching your validation errors in an easier way:


            <a:commandButton id="submit" 
               action="#{project.editProject}" 
               reRender="projectEdit"
               data="#{facesContext.maximumSeverity.ordinal ge 2}"
               oncomplete="if(data == false) Richfaces.hideModalPanel('projectPanel');"
               value="Submit"/>
            



            Cheers,


            Damian.

            • 3. Re: rich:modalPannel + validation + DataModelSelection
              Vincent Crepin Newbie

              Thank you Damian. In my case, I have approximately what you describe. Except the validation error catching which is great (I will use that).


              But my problem is when I hit cancel after some validation errors. When I return to the modal panel, my business object is the right one (the one I selected in the list) but the form stays in an invalid state with the previously wrong fields in red and when I try to use the normal functions of the modal panel, they do not act correctly as if there was validation errors.


              I'm wondering if the problem is not due to the fact that I rerender an outputPanel and not the entire form of the modal panel. I will try that.


              V.


              • 4. Re: rich:modalPannel + validation + DataModelSelection
                Vincent Crepin Newbie

                Rerendering the form eliminates the red attributes of the invalid fields. But the wrong behavior of the controls (wrong values of certain fields) are still present.


                V.

                • 5. Re: rich:modalPannel + validation + DataModelSelection
                  Damian Harvey Apprentice

                  It sounds very much like you're not resetting the values on the backend first. Put in some logging and see if this is the case.


                  • 6. Re: rich:modalPannel + validation + DataModelSelection
                    Vincent Crepin Newbie

                    To be precise, In my modal panel, I have an edition section and a list of items. I can switch item by clicking on it and it becomes the edited one. Everything works fine but when I generate a validation error (ex: saving a not populated object), I cannot use the interface appropriately from that point on. To switch object, there is a a4k:hyperlink that calls a backing bean method with ajaxSingle true to allow switching even if some validation errors are present in the edition section.


                    Here is the  relevant 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"
                            xmlns:s="http://jboss.com/products/seam/taglib"
                            xmlns:c="http://java.sun.com/jstl/core">
                    
                            <rich:modalPanel id="carEditModalPanel" autosized="true">
                                    <f:facet name="header">
                                            <h:outputText value="#{messages['KilometerEntry.myCar.label']}" />
                                    </f:facet>
                    
                                    <h:form id="carEditModalPanelForm">
                                            <a4j:outputPanel id="carEditPanel">
                                                    <table border="0" cellpadding="3" cellspacing="3">
                                                            <tr>
                                                                    <td><a4j:commandButton
                                                                            action="#{com_servier_hr_session_uievents_carEdit.consultEntriesForCurrentCar()}"
                                                                            value="#{messages['carEdit.cmdClose.label']}" immediate="true"
                                                                            bypassUpdates="true"
                                                                            oncomplete="javascript:Richfaces.hideModalPanel('carEditModalPanel')"
                                                                            status="carEditStatus"
                                                                            reRender="kilometerEntryMonthList, specificToolbarPanel">
                                                                    </a4j:commandButton></td>
                                                                    <td width="100%">
                                                                    <center><a4j:status id="carEditStatus" forceId="true">
                                                                            <f:facet name="start">
                                                                                    <h:graphicImage value="/img/spinner.gif" />
                                                                            </f:facet>
                                                                    </a4j:status></center>
                                                                    </td>
                                                            </tr>
                                                    </table>
                                                    <a4j:outputPanel ajaxRendered="true" bodyClass="panelBodySmall">
                                                            <h:messages id="error" globalOnly="true"></h:messages>
                                                    </a4j:outputPanel>
                                                    <a4j:outputPanel id="currentCarOutputPanel"
                                                            bodyClass="panelBodySmall">
                                                            <rich:panel id="currentCarPanel" bodyClass="#{com_servier_hr_session_uievents_carEdit.getEditBodyClass()}"
                                                                    rendered="#{carPanelRendered}">
                                                                    <table cellspacing="0" cellpadding="0" width="100%">
                                                                            <tr>
                                                                                    <td><s:decorate template="/layout/edit.xhtml">
                                                                                            <ui:define name="label">#{messages['KilometerEntry.carReceptionDate.label']}</ui:define>
                                                                                            <rich:calendar id="receptionDateCalendar"
                                                                                                    value="#{com_servier_hr_session_uievents_carEdit.currentCar.receptionDate}"
                                                                                                    locale="#{facesContext.viewRoot.locale}" popup="true"
                                                                                                    datePattern="MMM d yyyy HH:mm" showApplyButton="false"
                                                                                                    required="true">
                                                                                            </rich:calendar>
                                                                                    </s:decorate></td>
                                                                            </tr>
                                                                            <tr>
                                                                                    <td><s:decorate template="/layout/edit.xhtml">
                                                                                            <ui:define name="label">#{messages['KilometerEntry.carReceptionOdometer.label']}</ui:define>
                                                                                            <h:inputText id="receptionOdometerInput"
                                                                                                    value="#{com_servier_hr_session_uievents_carEdit.currentCar.kilometerStart}"
                                                                                                    size="24" maxlength="6" required="true">
                                                                                                    <f:converter converterId="javax.faces.Integer" />
                                                                                            </h:inputText>
                                                                                    </s:decorate></td>
                                                                            </tr>
                                                                            <tr>
                                                                                    <td><s:decorate template="/layout/edit.xhtml">
                                                                                            <ui:define name="label">#{messages['KilometerEntry.carReturnDate.label']}</ui:define>
                                                                                            <rich:calendar
                                                                                                    value="#{com_servier_hr_session_uievents_carEdit.currentCar.returnDate}"
                                                                                                    locale="#{facesContext.viewRoot.locale}" popup="true"
                                                                                                    datePattern="MMM d yyyy HH:mm" showApplyButton="false"
                                                                                                    required="false">
                                                                                            </rich:calendar>
                                                                                    </s:decorate></td>
                                                                            </tr>
                                                                            <tr>
                                                                                    <td><s:decorate template="/layout/edit.xhtml">
                                                                                            <ui:define name="label">#{messages['KilometerEntry.carReturnOdometer.label']}</ui:define>
                                                                                            <h:inputText
                                                                                                    value="#{com_servier_hr_session_uievents_carEdit.currentCar.kilometerEnd}"
                                                                                                    size="24" maxlength="6" required="true">
                                                                                                    <f:converter converterId="javax.faces.Integer" />
                                                                                                    <f:validateLongRange maximum="1000000" minimum="0" />
                                                                                            </h:inputText>
                                                                                    </s:decorate></td>
                                                                            </tr>
                                                                            <tr>
                                                                                    <td><a4j:commandButton id="saveCarButton"
                                                                                            value="#{messages['carEdit.carSave.label']}"
                                                                                            action="#{com_servier_hr_session_uievents_carEdit.saveCurrentCar()}"
                                                                                            reRender="currentCarOutputPanel" status="carEditStatus" /> <a4j:commandButton
                                                                                            disabled="#{com_servier_hr_session_uievents_carEdit.currentCar.new}"
                                                                                            id="newCarButton" value="#{messages['carEdit.carNew.label']}"
                                                                                            action="#{com_servier_hr_session_uievents_carEdit.newCar()}"
                                                                                            reRender="currentCarOutputPanel" status="carEditStatus" /></td>
                                                                            </tr>
                                                                    </table>
                                                            </rich:panel>
                                                            <rich:simpleTogglePanel switchType="client"
                                                                    bodyClass="panelBodySmall" label="#{messages['carList.title']}"
                                                                    opened="true">
                                                                    <rich:dataList rows="10"
                                                                            value="#{com_servier_hr_session_uievents_carEdit.allCars}"
                                                                            var="car" id="carList">
                                                                            <a4j:outputPanel
                                                                                    rendered="#{not car.equals(com_servier_hr_session_uievents_carEdit.currentCar)}">
                                                                                    <a4j:commandLink ajaxSingle="true"
                                                                                            action="#{com_servier_hr_session_uievents_carEdit.editCar(car)}"
                                                                                            reRender="carEditModalPanelForm"
                                                                                            status="carEditStatus">
                                                                                            <strong> <h:outputText
                                                                                                    value="#{messages['carEdit.receptionDate.label']}: "></h:outputText></strong>
                                                                                            <h:outputText value="#{car.formattedReceptionDate}" />
                                                                                            <strong> <h:outputText
                                                                                                    value="#{messages['carEdit.returnDate.label']}: "
                                                                                                    rendered="#{car.returnDate!=null}"></h:outputText></strong>
                                                                                            <h:outputText value="#{car.formattedReturnDate}" />
                                                                                            <strong> <h:outputText
                                                                                                    value="#{messages['carEdit.odometer.label']}: "></h:outputText></strong>
                                                                                            <h:outputText value="#{car.kilometerStart} " />- 
                                                                                    <h:outputText value="#{car.kilometerEnd} " />
                                                                                    </a4j:commandLink>
                                                                                    <br />
                                                                                    <rich:spacer width="4" />
                                                                                    <a4j:commandLink
                                                                                            action="#{com_servier_hr_session_uievents_carEdit.editCar(car)}"
                                                                                            ajaxSingle="true" reRender="carEditModalPanelForm"
                                                                                            status="carEditStatus">
                                                                                            <strong><h:outputLabel
                                                                                                    value="#{messages['KilometerEntryMonthList.contactName.label']}: " /></strong>
                                                                                            <h:outputText value="#{car.contact.fullName}" />
                                                                                    </a4j:commandLink>
                                                                            </a4j:outputPanel>
                                                                            <a4j:outputPanel
                                                                                    rendered="#{car.equals(com_servier_hr_session_uievents_carEdit.currentCar)}">
                                                                                    <strong> <h:outputText
                                                                                            value="#{messages['carEdit.receptionDate.label']}: "></h:outputText></strong>
                                                                                    <h:outputText value="#{car.formattedReceptionDate}" />
                                                                                    <strong> <h:outputText
                                                                                            value="#{messages['carEdit.returnDate.label']}: "
                                                                                            rendered="#{car.returnDate!=null}"></h:outputText></strong>
                                                                                    <h:outputText value="#{car.formattedReturnDate}" />
                                                                                    <strong> <h:outputText
                                                                                            value="#{messages['carEdit.odometer.label']}: "></h:outputText></strong>
                                                                                    <h:outputText value="#{car.kilometerStart} " />- 
                                                                                    <h:outputText value="#{car.kilometerEnd} " />
                                                                                    <br />
                                                                                    <rich:spacer width="4" />
                                                                                    <strong><h:outputLabel
                                                                                            value="#{messages['KilometerEntryMonthList.contactName.label']}: " /></strong>
                                                                                    <h:outputText value="#{car.contact.fullName}" />
                                                                            </a4j:outputPanel>
                    
                                                                            <rich:separator height="5"></rich:separator>
                                                                    </rich:dataList>
                                                                    <rich:datascroller for="carList" id="carListScroller"
                                                                            maxPages="30"></rich:datascroller>
                                                            </rich:simpleTogglePanel>
                                                    </a4j:outputPanel>
                                            </a4j:outputPanel>
                                    </h:form>
                            </rich:modalPanel>
                            <script type="text/javascript">
                                    //<![CDATA[
                                            function windowcloseCarEditModalPanel(){
                                                    if (document.getElementById('carEditModalPanelForm:error')==null){
                                                            Richfaces.hideModalPanel('carEditModalPanel');
                                                    };
                                            };
                                    //]]>
                    
                            </script>
                    </ui:composition>
                    




                    and the backing bean method:



                    @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
                            public String editCar(EmployeeCar car) {
                                    this.currentCar = car;
                                    facesMessages.clear();
                    
                                    return null;
                            }






                    The object is switched on the server side (I debugged to see) and in the interface, the dates are switched to the right values but not the 2 inputText (receptionOdometer and returnOdometer).


                    V.

                    • 7. Re: rich:modalPannel + validation + DataModelSelection
                      Damian Harvey Apprentice

                      If some inputText fields aren't being switched then it sounds like you may need a <a4j:region> in there somewhere. I know it's needed (due to an RF bug) to get <h:selectOneMenu> to reRender inputTexts so maybe the same applies to you.


                      Try in several places eg around your form.


                      Cheers,


                      Damian.

                      • 8. Re: rich:modalPannel + validation + DataModelSelection
                        Vincent Crepin Newbie

                        Yep, this is something like that. I put some outputTexts to accompany the problematic inputTexts and they are reRendered correctly (the good values).


                        I'm playing with the region right now. Tried it in many places without success.


                        Will continue to investigate...

                        • 9. Re: rich:modalPannel + validation + DataModelSelection
                          Vincent Crepin Newbie

                          Also tried with an inplaceInput. Does not work...


                          V.