10 Replies Latest reply on Feb 12, 2014 11:44 AM by mekkimoh

    (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values

    mekkimoh

      Hi,

       

      I had a look to the Show Case (see link below), while trying to use a PopUp Panel to edit data from a Data Table :

       

      http://livedemo.exadel.com/richfaces4-demo/richfaces/component-sample.jsf?demo=dataTable&sample=dataTableEdit&skin=classic

       

      I noticed some irregular behavior when following the scenario described below :

       

      1 - Choose one line (lets call it alpha) and click the edition icon to edit it.

           Result: a pop up panel is displayed inviting you to edit data.

      2 - Trigger a validation error, for example, by leaving the "VIN" field empty and then clicking the "Store" button.

           Result: the pop up panel is still displayed and a validation error invites you to put a value for the "VIN" field

      3 - Click the "Cancel" Button.

           Result: the pop up panel is then hidden.

      4 - Choose a different line (lets call it beta) to edit and click the corresponding edition icon.

           Result: Again, a pop up panel is displayed inviting you to edit data

           PROBLEM: "mileage" and "price" fields do not contain values of line beta (as expected)

                               but those of line alpha ...

       

      Can anyone explain the reason of such behavior and how could it be fixed ?

       

      Thank you in advance.

        • 1. Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
          liuliu

          It is because the modalpanel is in the same form of datatable. You need add execute="@this" on the commandbutton to fix this problem.

          or put the modalpanel in another form.

          • 2. Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
            mekkimoh

            Hi Liumin,

             

            First of all, thank you for your interest.

             

            1 - Using two different forms

            Before looking in the ShowCase i tried several configurations where two forms were used:

            one for the dataTable and another one for the popupPanel, including settings where the second form

            was containing or contained by the popupPanel, and none was working perfectly.

            Could you provide some sample code working with different forms and providing the functionality described above,

            i.e editing rows in a popupPanel ?

             

            2 - execute="@this"

            I also tried your suggestion to add execute="@this" to the command button,

            presuming you were referring to the edition cancel commandButton.

             

            Changing :

             

            <a4j:commandButton value="Cancel" onclick="#{rich:component('editPane')}.hide(); return false;" />

             

            To

             

            <a4j:commandButton execute="@this" value="Cancel" onclick="#{rich:component('editPane')}.hide(); return false;" />

             

            did not work. Values in the popupPanel are still outdated if a validation failure is triggered before.

             

            The same trick did not work with the the edition confirmation commandButton (Store), worst: updates no longer work

            if i change execute="editPane" to execute="@this".

             

            3 - Further Googling the Problem

            Meanwhile i further googled the problem and it seems to be a classical problem with Input Components.

            See the community link below:

             

            Validation and refresh problems...

             

            Many solutions are proposed but they only apply to previous releases of RichFaces.

            I am still trying to make these tricks work for Release 4, and i'll update this thread accordingly.

            • 3. Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
              liuliu

              sorry for my imprecision


              1 you cant have nested form in jsf(html). so when use seperate form, you need remove domElementAttachment attribute on popuppanel, and form in the popuppanel.


              2 execute="@this" to avoid the submit of the entire form that is why you fail on validation, so you should put on the action component, that means the edit commandlink.

              • 4. Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
                mekkimoh

                2 : Actually i really need that validation failure.

                When the edition leaves data in an inconsistent state (typical example: required input left empty),

                the user should be notified and invited to correct input.

                Although when the user effectively corrects input and retries to store provided valid input things work perfectly.

                Things go wrong when he decides instead to cancel the edition (so the edition popupPanel is closed leaving the form in an inconsistent validation status)

                and chooses a different row to edit. In this case the edition popupPanel shows the old data.

                Curiously only fields that were left empty in the first edition trial are updated with values from second row,

                all other ones take the values of the first row.

                 

                Below you can see the commandLink that triggers the edition popupPanel:

                 

                                <a4j:commandLink styleClass="no-decor" render="editGrid" execute="@this"

                                    oncomplete="#{rich:component('editPane')}.show()">

                                    <h:graphicImage value="/images/icons/edit.gif" alt="edit" />

                                    <a4j:param value="#{it.index}" assignTo="#{carsBean.currentCarIndex}" />

                                    <f:setPropertyActionListener target="#{carsBean.editedCar}" value="#{car}" />

                                </a4j:commandLink>

                 

                 

                You can first notice that the execute="@this" is there.

                Then you can see that a  f:setPropertyActionListener takes care of updating the carsBean.editedCar field,

                which is used to fill input fields in the popupPanel with values of the selected row in the dataTable.

                Curiously this update is not exhaustive since it only addresses fields that were left empty (null) in carsBean.editedCar.

                The explanation i found for this is that JSF uses in priority submittedValue of the UIComponent to compute its final value

                and not its bound value in the backing bean ... This explains why only inputs having null submittedValues are updated:

                for them JSF went to the backing bean to get values.

                I tried several tricks to nullify submittedValues  for properties of carsBean.editedCar and thus force JSF

                to get fresh values from the backing bean for all inputs without success.


                Since problems come from validation errors (after that f:setPropertyActionListener behaves strangely) i was thinking about leveraging all constraints on inputs

                (remove all required = "true" and use String for all fields even numerical ones) and handle validation by hand : close the popupPanel if input is correct,

                or let it open and enrich with error messages for every input, i am pretty confident that this should work but it is somehow "dirty" coding ...


                Sorry for the long explanation and i hope i correctly understood what you suggested.


                1 : off course nested forms are not allowed ...

                • 5. Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
                  liuliu

                  hi,

                   

                  I dont understand your problem. if you have a validation error, the update value phase should be skipped. If you want the user correct their input, dont close the popuppanel after save. if you want skip validation error, use execute="@this".

                   

                  your need post your xhtml(datatable and popuppanel) and backingbean code.

                   

                  by the way in jsf2, you can use the method with parameter in action of commandlink, it is easier than f:setPropertyActionListener.

                  • 6. Re: Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
                    mekkimoh

                    Hi again,

                     

                    Here come Code Snippets.

                    More or less an adaptation of ShowCase:

                    http://showcase.richfaces.org/richfaces/component-sample.jsf?demo=dataTable&sample=dataTableEdit&skin=blueSky

                     

                    XHTML Page

                    <?xml version="1.0" encoding="UTF-8"?>
                    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                    <html xmlns="http://www.w3.org/1999/xhtml"
                      xmlns:h="http://java.sun.com/jsf/html"
                      xmlns:ui="http://java.sun.com/jsf/facelets"
                      xmlns:f="http://java.sun.com/jsf/core"
                      xmlns:rich="http://richfaces.org/rich"
                      xmlns:a4j="http://richfaces.org/a4j"
                    >
                      <h:head/>
                      <h:body>
                        <a4j:status
                          onstart="#{rich:component('statutPanel')}.show()"
                          onstop="#{rich:component('statutPanel')}.hide()"
                        />
                        <h:form id="coffeesForm">
                          <center>
                            <rich:dataTable
                              id="listCoffeesRDT"
                              value="#{coffeeBean.coffees}"
                              var="coffee"
                              iterationStatusVar="it"
                              rows="3"
                              rendered="true"
                            >
                              <f:facet name="header">
                                <h:outputText value="Coffee Shop" />
                              </f:facet>
                              <rich:column>
                                <f:facet name="header">
                                  <h:outputText value="id" />
                                </f:facet>
                                <h:outputText value="#{coffee.id}"  />
                              </rich:column>
                              <rich:column>
                                <f:facet name="header">
                                  <h:outputText value="name" />
                                </f:facet>
                                <h:outputText value="#{coffee.name}"  />
                              </rich:column>
                              <rich:column>
                                <f:facet name="header">
                                  <h:outputText value="price" />
                                </f:facet>
                                <h:outputText value="#{coffee.price}"  />
                              </rich:column>
                              <rich:column>
                                <f:facet
                                  name="header"
                                />
                                <a4j:commandLink
                                  execute="@this"
                                  render="@none"
                                  oncomplete="#{rich:component('deleteCoffeeConfirmationPanel')}.show()"
                                >
                                  <h:graphicImage
                                    value="../resources/images/delete.gif"
                                    title="delete"
                                    alt="delete"
                                  />
                                  <a4j:param
                                    value="#{it.index}"
                                    assignTo="#{coffeeBean.currentCoffeeIndex}"
                                  />
                                </a4j:commandLink>
                                <a4j:commandLink
                                  render="editGrid"
                                  execute="@this"
                                  oncomplete="#{rich:component('editCoffeePanel')}.show()"
                                >
                                  <h:graphicImage
                                    value="../resources/images/edit.gif"
                                    title="edit"
                                    alt="edit"
                                  />
                                  <a4j:param
                                    value="#{it.index}"
                                    assignTo="#{coffeeBean.currentCoffeeIndex}"
                                  />
                                  <f:setPropertyActionListener
                                    target="#{coffeeBean.coffee}"
                                    value="#{coffee}"
                                  />
                                </a4j:commandLink>
                              </rich:column>
                              <f:facet name="footer">
                                <rich:dataScroller
                                  id="listCoffeesRDS"
                                  page="#{coffeeBean.currentPage}"
                                />
                              </f:facet>
                            </rich:dataTable>
                            <a4j:jsFunction
                              name="deleteCoffee"
                              action="#{coffeeBean.deleteCoffee}"
                              render="listCoffeesRDT"
                              execute="@this"
                              oncomplete="#{rich:component('deleteCoffeeConfirmationPanel')}.hide();"
                            />
                            <rich:popupPanel
                              id="statusPanel"
                              autosized="true"
                              resizeable="false"
                            >
                              <h:graphicImage
                                value="../resources/images/wait.gif"
                                title="wait"
                                alt="wait"
                              />
                              Please wait ...
                            </rich:popupPanel>
                            <rich:popupPanel
                              id="deleteCoffeeConfirmationPanel"
                              autosized="true"
                              resizeable="false"
                            >
                              Do you really want to delete Coffee Entry ?
                              <a4j:commandButton
                                value="cancel"
                                onclick="#{rich:component('deleteCoffeeConfirmationPanel')}.hide(); return false;"
                              />
                              <a4j:commandButton
                                value="delete"
                                onclick="deleteCoffee(); return false;"
                              />
                            </rich:popupPanel>
                            <rich:popupPanel
                              id="editCoffeePanel"
                              domElementAttachment="parent"
                              autosized="true"
                              resizeable="false"
                            >
                              <f:facet name="header">
                                  <h:outputText value="Update Coffee" />
                              </f:facet>
                              <h:panelGrid
                                columns="3"
                                id="editGrid"
                              >
                                <h:outputText styleClass="title-text" value="id" />
                                <h:outputText styleClass="data-text" value="#{coffeeBean.coffee.id}"  />
                                <h:panelGroup />
                                <h:outputText styleClass="title-text" value="name" />
                                <h:inputText
                                  id="editCoffeeNameIn"
                                  value="#{coffeeBean.coffee.name}"
                                  maxlength="10"
                                  size="10"
                                  required="true"
                                />
                                <rich:message for="editCoffeeNameIn" />
                                <h:outputText styleClass="title-text" value="price" />
                                <h:inputText
                                  id="editCoffeePriceIn"
                                  value="#{coffeeBean.coffee.price}"
                                  maxlength="6"
                                  size="6"
                                  required="true"
                                />
                                <rich:message for="editCoffeePriceIn" />
                              </h:panelGrid>
                              <a4j:commandButton
                                value="update"
                                action="#{coffeeBean.editCoffee}"
                                render="listCoffeesRDT"
                                execute="editCoffeePanel"
                                oncomplete="if (#{facesContext.maximumSeverity==null}) {#{rich:component('editCoffeePanel')}.hide();}"
                              />
                              <a4j:commandButton
                                value="cancel"
                                onclick="#{rich:component('editCoffeePanel')}.hide(); return false;"
                              />
                            </rich:popupPanel>
                            <h:commandLink
                              value="Initialize"
                              action="#{coffeeBean.init}"
                            />
                          </center>
                        </h:form>
                      </h:body>
                    </html>
                    

                     

                    CoffeeBean.java

                    import java.io.Serializable;
                    import java.util.ArrayList;
                    import javax.annotation.PostConstruct;
                    import javax.annotation.PreDestroy;
                    import org.springframework.context.annotation.Scope;
                    import org.springframework.stereotype.Controller;
                    
                    
                    @Controller
                    @Scope("session")
                    public class CoffeeBean implements Serializable
                    {
                      private static final long serialVersionUID = 1L;
                    
                    
                      private ArrayList<Coffee> coffees;
                      private Coffee coffee;
                      private Integer currentCoffeeIndex;
                      private Integer currentPage;
                    
                      // Getters/Setters ...
                    
                      @PostConstruct
                      public void init()
                      {
                        clean();
                      }
                    
                      @PreDestroy
                      public void clean()
                      {
                        setCoffees(new ArrayList<Coffee>());
                        getCoffees().add(new Coffee(1,"Arabica",11.99f));
                        getCoffees().add(new Coffee(2,"Robusta",12.99f));
                        getCoffees().add(new Coffee(3,"Liberia",13.99f));
                        getCoffees().add(new Coffee(4,"Skybury",14.99f));
                        setCoffee(null);
                        setCurrentCoffeeIndex(null);
                        setCurrentPage(null);
                      }
                    
                      public void deleteCoffee()
                      {
                        getCoffees().remove(getCoffees().get(getCurrentCoffeeIndex()));
                      }
                    
                      public void editCoffee()
                      {
                        getCoffees().set(getCurrentCoffeeIndex(), getCoffee());
                      }
                    }
                    

                     

                    Coffee.java

                    import java.io.Serializable;
                    
                    
                    public class Coffee implements Serializable
                    {
                      private static final long serialVersionUID = 1L;
                    
                      private Integer id;
                      private String name;
                      private Float price;
                    
                      // Getters/Setters ...
                    
                      public Coffee()
                      {
                    
                      }
                    
                      public Coffee(Integer id, String name, Float price) {
                        super();
                        this.id = id;
                        this.name = name;
                        this.price = price;
                      }
                    
                      // Eclipse Generated equals/hashCode methods
                      // involving id, name and price.
                    }
                    

                     

                    Screenshots describing the problem:

                     

                    1. Data Table with for each row delete and edit icons:

                    CoffeeShop1.png

                    2. Click on edit icon of row with id = 1:

                    CoffeeShop2.png


                    3. Leaving price field empty then click on update button, validation error message is displayed:

                    CoffeeShop3.png


                    4. Click on Cancel, then click on edit icon of row with id = 2:

                    CoffeeShop4.png

                    id is displayed correctly, but name and price come from previous canceled edit ...


                    REMARK: If in stead of leaving price field empty one leaves name field empty in step 3,

                    result in step 4. would be:

                    id : 2 (correct value)

                    name : Robusta (correct value)

                    price : 11.99 (wrong value)

                    Maybe somehow due to the special status of String objects in Java ?


                    • 7. Re: Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
                      liuliu

                      could you show getCoffee of CoffeeBean? just simple getter?

                       

                      if you continue edit the 3rd line, you have the same pb?

                      • 8. Re: Re: Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
                        mekkimoh

                        1. Yes the getter is a regular one.


                        CoffeeBean.java (getters/setters):

                          public ArrayList<Coffee> getCoffees() {
                            return coffees;
                          }
                          public void setCoffees(ArrayList<Coffee> coffees) {
                            this.coffees = coffees;
                          }
                          public Coffee getCoffee() {
                            return coffee;
                          }
                          public void setCoffee(Coffee coffee) {
                            this.coffee = coffee;
                          }
                          public Integer getCurrentCoffeeIndex() {
                            return currentCoffeeIndex;
                          }
                          public void setCurrentCoffeeIndex(Integer currentCoffeeIndex) {
                            this.currentCoffeeIndex = currentCoffeeIndex;
                          }
                          public Integer getCurrentPage() {
                            return currentPage;
                          }
                          public void setCurrentPage(Integer currentPage) {
                            this.currentPage = currentPage;
                          }
                        

                         

                        Coffee.java (getters/setters):

                          public Integer getId() {
                            return id;
                          }
                          public void setId(Integer id) {
                            this.id = id;
                          }
                          public String getName() {
                            return name;
                          }
                          public void setName(String name) {
                            this.name = name;
                          }
                          public Float getPrice() {
                            return price;
                          }
                          public void setPrice(Float price) {
                            this.price = price;
                          }
                        

                         

                        Something that looked strange to me: i added some display of coffeeBean.coffee

                        in the rich:popupPanel identified by "editCoffeePanel", its value was null all the time ...

                        Same thing if i display it outside the rich:popupPanel just before closing the form.

                         

                        2. When i continue editing the 3rd row i encounter the same problem,

                        but i worked this out by transforming lines 170-173 of the XHTML page to:

                         

                                  <a4j:commandButton
                                    value="cancel"
                                    action="#{coffeeBean.cleanCoffee}"
                                    oncomplete="#{rich:component('editCoffeePanel')}.hide(); return false;"
                                  />
                        

                         

                        where cleanCoffee() method is (as expected) defined as follows:

                         

                          public void cleanCoffee()
                          {
                            setCoffee(null);
                          }
                        

                         

                        With those updates to the code, edition of third row becomes flawless:

                        So to summarize:

                        "edit + validation error + cancel" => "next edit is erroneous"

                        "edit + validation error + cancel + many(edit without validation error or simple cancel)" => "next edit is correct"

                        • 9. Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
                          michpetrov

                          This is unfortunately a design choice of JSF (JSF-1060), after a validation error it won't rerender the input components, unless they are null.

                          1 of 1 people found this helpful
                          • 10. Re: (RichFaces ShowCase, rich:dataTable, Data Table Edit): Edition PopUp Panel holds old values
                            mekkimoh

                            Thanks Michal.

                             

                            I've read to much about this, including here Validation and refresh problems... where people proposed indeed to nullify submitted values of Components before re-rendering and thus force JSF to take again values from the backing bean. It seems that solutions like here Re: Validation and refresh problems... was working with versions of RichFaces previous to 4. I tried to reuse the same idea with Version 4 (even if some classes are now missing) without success. I'll update the thread if things get better.

                             

                            For now the quick and dirty solution would be to avoid JSF validation "police" by removing all constraints on input fields and handle by hand the validation ...

                            Or maybe a cleaner solution (with the risk of driving the user crazy) would be to remove the cancel button and leave the user with no way to close the modal popupPanel other than after a successful update ...