views:

966

answers:

4

I am adding (UIInput) to the footer columns (UIColumn) of a datatable (UIData) created dynamically. The UIData is bound to a datatable tag in the jsp. In the datatable, I just have headers and footers with the header having the labels and footer having the corresponding value in editable textbox. When I change the value and submit the form using a commandButton and I try to access the UIInput value using .getValue() in the action method, I just get the old values and not the values updated in the page. I tried binding it to an attribute in the backing bean and checked the values being set in the setter. I notice that the old values are being set and the values I updated in the page do not reflect in the action method or setter. I tried using .getValue, .getLocalValue, .getSubmittedValue. None of these give me the new values. Any suggestions what I might be doing worng?

A: 

The actual code does several other processing, but below code should help in replicating the issue. In the below code, I expect the TestString to output the modified values from the page. But it just returns old values. Below is the jsp:

<%@taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<html>
<head>
</head>
<f:view>
    <body>
     <h:form styleClass="form" id="form1">
      <h:commandButton value="Save" action="#{TestPageBackingBean.save}" styleClass="commandExButton"/>
      <h:outputText styleClass="label" value="Header Table"/>
      <h:dataTable binding="#{TestPageBackingBean.headerDataTable}"></h:dataTable>
     </h:form>
    </body>
</f:view>
</html>

Below is the faces config:

<managed-bean>
 <managed-bean-name>TestPageBackingBean</managed-bean-name>
 <managed-bean-class>test.jsf.TestPageBackingBean</managed-bean-class>
 <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

Below is the backing bean code:

package test.jsf;

import java.io.IOException;

import javax.faces.component.UIColumn;
import javax.faces.component.UIData;
import javax.faces.component.UIInput;
import javax.faces.component.UIOutput;
import javax.faces.context.FacesContext;

public class TestPageBackingBean {

  private UIData headerDataTable = new UIData();

  public TestPageBackingBean() {

  }

  public UIData getHeaderDataTable()
    {    
         return getHeaderTable(headerDataTable);
    }       

  public UIData getHeaderTable(UIData dataTable)
    {    
       for (int i=0;i<10;++i)
       {
        dataTable.getChildren().add(getColumn(i));
       }
     return dataTable;
    }

    private UIColumn getColumn(int i)
  {
    UIOutput outputLabelText = new UIOutput();
     UIInput inputFieldText = new UIInput(); 
     UIColumn column = new UIColumn();

     outputLabelText.setValue("Label" + i);
     inputFieldText.setValue("test input" + i);

     column.setHeader(outputLabelText);
     column.setFooter(inputFieldText);
     return column;
    }

    public String save() throws IOException {
         String TestString = "";
            FacesContext ctx = FacesContext.getCurrentInstance();
            if (!ctx.getResponseComplete()) {
             for (int i=0; i<headerDataTable.getChildren().size();++i)
             {
              TestString = TestString + (String)((UIInput)((UIColumn) headerDataTable.getChildren().get(i)).getFooter()).getValue();
             }
          System.out.println(TestString);
            }
           return "save";
        }

    public void setHeaderDataTable(UIData headerDataTable) {
     this.headerDataTable = headerDataTable;
    } 
}
Krishna
+1  A: 

I tried running your demo code code under MyFaces 1.2.3 on Tomcat and Mojarra 2.0.0 Beta on Glassfish, but was unable to reproduce the problem - the save() method printed the values I entered into the fields.

(To use MyFaces, I had to change new UIData() to new HtmlDataTable(), probably due to how they implement the table renderer, but that is a minor change.)

I will note a couple of things about the bean:

  • the table getter will keep adding columns every time it is called - like on a page refresh with server-side state saving
  • keeping a reference to a UIComponent in a session bean usually is not a good idea; you would be better off using request scope for component bindings
    • session beans are supposed to implement Serializable (though I realize not everyone does this) and UIComponents cannot be serialized
    • your component might end up in multiple views if the user opens the page twice - concurrency issues
    • according to the spec: when JSF creates the view, it will use the component bound via the getter; but, when it restores the view (on submit), it will set the component via the setter, so keeping a reference is (at best) redundant

You might want to change the getter to something like this:

private UIData headerDataTable;

public UIData getHeaderDataTable() {
    if (headerDataTable == null) {
        headerDataTable = new UIData();
        getHeaderTable(headerDataTable);
    }
    return headerDataTable;
}

I am not confident that these changes will fix your issue, though - if you are still having trouble, try again with more details - your JSF implementation, the version, and the value of the *javax.faces.STATE_SAVING_METHOD* parameter in web.xml (if any).

McDowell
A: 

The issue is not fully resolved yet.

I use RSA 7, with IBM JSF - Base Faces Support 7.0 and Enhanced Faces Components 7.0 on WAS 6.0 The javax.faces.STATE_SAVING_METHOD was 'server' by default.

I tried changing STATE_SAVING_METHOD to 'client'. It did print the changed value in the output but in label4 instead of label0 which I modified. On the next submit the value moved from label4 to label8. Seemed inconsistent.

Krishna
A: 

I managed to workaround by pulling the values from requestParameterMap. If there is a fix for the issue please do let me know. McDowell - thanks for your inputs.

Krishna