5 Replies Latest reply on Apr 2, 2009 7:08 AM by cdanielw

    Edit dataTable row in modalPanel

    cdanielw Newbie

      I am trying to edit a row from a dataTable in a modalPanel. Everything seems to work fine at first glance, but there turned out to be a big problem that I can't seem to find my way around.

      Below is the code I'm trying to get to work

      <?xml version='1.0' encoding='UTF-8'?>
      <html xmlns="http://www.w3.org/1999/xhtml"
       xmlns:f="http://java.sun.com/jsf/core"
       xmlns:h="http://java.sun.com/jsf/html"
       xmlns:rich="http://richfaces.org/rich"
       xmlns:a4j="http://richfaces.org/a4j">
      <head><title>Edit dataTable row in modalPanel Test</title></head>
      <body>
      
      <rich:modalPanel id="modalPanel" showWhenRendered="#{validation.failed}">
       <h:form>
       <h:panelGrid columns="3">
       <h:outputLabel for="firstName" value="First name"/>
       <h:inputText id="firstName" value="#{personController.person.firstName}" required="true"/>
       <h:message for="firstName" style="color: red"/>
      
       <h:outputLabel for="lastName" value="Last name"/>
       <h:inputText id="lastName" value="#{personController.person.lastName}" required="true"/>
       <h:message for="lastName" style="color: red"/>
       </h:panelGrid>
      
       <a4j:commandButton value="Save" action="#{personController.savePerson}" reRender="modalPanel, persons"/>
       <input type="button" value="Close" onclick="#{rich:component('modalPanel')}.hide();"/>
       </h:form>
      </rich:modalPanel>
      
      <h:form>
       <rich:dataTable id="persons" var="person" value="#{personController.persons}"
       onRowMouseOver="this.style.backgroundColor='#FBE7C9';"
       onRowMouseOut="this.style.backgroundColor='white';">
       <rich:column>
       <f:facet name="header">
       First name
       </f:facet>
       <h:outputText value="#{person.firstName}"/>
       </rich:column>
       <rich:column>
       <f:facet name="header">
       Last name
       </f:facet>
       <h:outputText value="#{person.lastName}"/>
       </rich:column>
      
       <a4j:support event="onRowClick" reRender="modalPanel" action="#{personController.setPerson(person)}"
       oncomplete="#{rich:component('modalPanel')}.show();">
       </a4j:support>
       </rich:dataTable>
      </h:form>
      </body>
      </html>
      


      @Name("personController")
      @Scope(ScopeType.PAGE)
      public class PersonController {
       private static final List<Person> PERSONS = Arrays.asList(new Person("A", "B"), new Person("C", "D"));
       private Person person;
      
       public List<Person> getPersons() { return PERSONS; }
      
       public Person getPerson() { return person; }
      
       public void setPerson(Person person) { this.person = person; }
      
       public void savePerson() {
       System.out.println("Person saved: " + person);
       person = null;
       }
      }


      public class Person {
       private String firstName;
       private String lastName;
      
       public Person(String firstName, String lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
       }
      
       public String getFirstName() { return firstName; }
      
       public void setFirstName(String firstName) { this.firstName = firstName; }
      
       public String getLastName() { return lastName; }
      
       public void setLastName(String lastName) { this.lastName = lastName; }
      
       @Override
       public String toString() {
       return firstName + ' ' + lastName;
       }
      }


      - Select the first row
      - Empty the first name field (A)
      - Click save and get a validation error
      - Click cancel
      - Select the second row

      The first name is C as expected. The last name is however B.

      This is my problem. The state of the input field components are stored between the edit operations, and I can't find a way to reset it. Any suggestions on how to solve this?



        • 1. Re: Edit dataTable row in modalPanel
          cdanielw Newbie

          Sorry for replying to myself. I just found the exact same use-case in the RichFaces demo (which I guess I should have checked out before posting in the first place)

          http://livedemo.exadel.com/richfaces-demo/richfaces/dataTable.jsf?tab=editDataTable

          This page has exactly the same issue I've got.

          - Edit the first row
          - Set value in all fields to 'test'
          - Click Store and get validation error
          - Edit another row

          Now the Make and Model is 'test' and 'test' on this row too.

          • 2. Re: Edit dataTable row in modalPanel
            cdanielw Newbie

            Here I go again.

            This issue with the demo app is already reported (RF-5468), but has been closed as a duplicate of RF-5400. I would say that was a mistake - the two issues are different. Maybe RF-5468 could be re-opened?

            • 3. Re: Edit dataTable row in modalPanel
              Ilya Shaikovsky Master

              thanks I reopened the issue. watch it to be updated with a solution

              • 4. Re: Edit dataTable row in modalPanel
                cdanielw Newbie

                An ugly workaround, but one that do seem to work, is to manually reset the state of the modalPanel child components when editing a row.

                I added the following to PersonController

                public void onEdit(ActionEvent event) {
                 UIComponent modalPanel = FacesContext.getCurrentInstance().getViewRoot().findComponent("modalPanel");
                 resetComponent(modalPanel);
                 }
                
                 public void resetComponent(UIComponent component) {
                 if (component instanceof EditableValueHolder) {
                 EditableValueHolder editableValueHolder = (EditableValueHolder) component;
                 editableValueHolder.setValue(null);
                 }
                 for (UIComponent child : component.getChildren()) {
                 resetComponent(child);
                 }
                 }


                and added the onEdit actionListener to the a4j:support tag

                • 5. Re: Edit dataTable row in modalPanel
                  cdanielw Newbie

                  Another more reusable solution, though still ugly, would be the following:

                  public class ResetComponentActionListener implements ActionListener {
                   private static final String ATTRIBUTE_NAME = "componentToReset";
                  
                   public void processAction(ActionEvent event) throws AbortProcessingException {
                   Map<String, String> parameters = FacesContext.getCurrentInstance().getExternalContext()
                   .getRequestParameterMap();
                   if (parameters.containsKey(ATTRIBUTE_NAME)) {
                   String componentId = parameters.get(ATTRIBUTE_NAME);
                   UIComponent componentToReset = FacesContext.getCurrentInstance().getViewRoot()
                   .findComponent(componentId);
                   if (componentToReset == null) {
                   throw new AbortProcessingException("Component not found: " + componentId);
                   }
                   resetComponent(componentToReset);
                   } else {
                   throw new AbortProcessingException("Component " + event.getComponent()
                   + " doesn't have required attribute: " + ATTRIBUTE_NAME);
                   }
                   }
                  
                   private void resetComponent(UIComponent component) {
                   if (component instanceof EditableValueHolder) {
                   EditableValueHolder editableValueHolder = (EditableValueHolder) component;
                   editableValueHolder.setValue(null);
                   }
                   for (UIComponent child : component.getChildren()) {
                   resetComponent(child);
                   }
                   }
                  }
                  



                  <a4j:support event="onRowClick" reRender="modalPanel" action="#{personController.setPerson(person)}"
                   oncomplete="#{rich:component('modalPanel')}.show();">
                   <f:param name="componentToReset" value="modalPanel"/>
                   <f:actionListener type="org.fao.foris.meeting.web.ResetComponentActionListener"/>
                   </a4j:support>