Primefaces Nested DataTable with InputText Not Updating Bean

236 Views Asked by At

I've a dataTable within a dataTable. The initial dataTable has a list of components that appear on the page. One of these components will be a list of strings which can have elements added or deleted. When I change a string in this list, I expect the value to show up in the bean and it is not.

Below I have an example of my problem. The page renders a text input field for the first component then three text input fields to represent the second component which is a list of three input fields.

I have valueChange listener on all the input fields. The listener, is in the InnerBean class, prints out the source and the value that changed.
For the standalone input field, the listener correctly prints out the changed value and shows that the bean has been updated with this value. For any of the input fields from the list, the listener prints out the previous value of the input field and the bean has not been updated. On the ajax update of the inner datatable, the changed value is replace with the original value.

Since the valueChange listener is called, it appears that Primefaces knows that the value has changed. The code just doesn't seem to record the changed value.

Any help is appreciated.

I'm using Primefaces 8.0 and JSF 2.2.20.

Here is the xhtml:

                <p:panel id="testPanel" header="#{myController.outerBean.name}" toggleable="true" collapsed="false" >
                    
                    <p:dataTable id="testTable" value="#{myController.outerBean.innerBeanList}" var="bean">
                        
                        <p:column >
                        
                            <!-- TEXT COMPONENT-->
                            <h:panelGroup rendered="#{bean.type eq 'text'}" >
                                <p:inputText id="textfield" value="#{bean.value}" style="width:100%;" >
                                    <p:ajax event="valueChange" listener="#{bean.textListListener}"  update="testTable" />
                                </p:inputText>
                            </h:panelGroup>
                            
                            <!-- LIST COMPONENT -->
                            <h:panelGroup rendered="#{bean.type eq 'textlist'}" >
                                <p:dataTable id="testListTable" styleClass="datatableWithoutBorder" style="width:320px" 
                                        var="textAddition" value="#{bean.list}" rowIndexVar="rowIndex" >    
                                    <p:column >
                                        <p:inputText id="textAdd" value="#{textAddition}" style="width: 100%;">
                                            <p:ajax event="valueChange" listener="#{bean.textListListener}" update="testListTable"/>                                            
                                        </p:inputText>
                                    </p:column>
                                </p:dataTable>
                            </h:panelGroup>
                            
                        </p:column>
                    </p:dataTable>

                    <h:panelGrid columns="1"  style="width:100%;">
                        <h:panelGroup style="float:right">
                            <p:commandButton id="submitBtn" value="Submit"
                                action="#{dummyController.submit}"
                                update="messages @this" 
                                icon="fa fa-save"/>
                        </h:panelGroup>
                    </h:panelGrid>
                </p:panel>

My controller code:

public class MyController {

private OuterBean outerBean;

public MyController() {
    System.out.println("MyController instantiated");
    setOuterBean(new OuterBean());
}

public void submit() {
    for (InnerBean ab: outerBean.getInnerBeanList()) {
        System.out.println(ab.getLabel() + ": " + ab.getValue() + ":" + ab.getList() );
    }
}

public void clear() {
    // TODO
}

// Getter/Setter methods
public OuterBean getOuterBean() {
    return outerBean;
}
public void setOuterBean(OuterBean outerBean) {
    this.outerBean = outerBean;
}

}

My OuterBean with the list of components:

public class OuterBean implements Serializable {

private String name;
private String value;
private List<InnerBean> innerBeanList;

public OuterBean() {

    name = "Entry Panel #1";
    value = "";

    innerBeanList = new ArrayList<InnerBean>();
    InnerBean ab1 = new InnerBean(); 
    ab1.setLabel("First Component");
    ab1.setType("text");
    ab1.setValue("Input text");
    innerBeanList.add(ab1);
    
    InnerBean ab2 = new InnerBean();
    ab2.setLabel("Second Component");
    ab2.setType("textlist");
    ArrayList<String> list = new ArrayList<String>();
    list.add("Item 1");
    list.add("Item 2");
    list.add("Item 3");
    ab2.setList(list);
    innerBeanList.add(ab2);
}

//
// Getter/Setters
//
public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getValue() {
    return value;
}

public void setValue(String value) {
    this.value = value;
}

public List<InnerBean> getInnerBeanList() {
    return innerBeanList;
}

public void setInnerBeanList(List<InnerBean> innerBeanList) {
    this.innerBeanList = innerBeanList;
}

}

My InnerBean which represents a component to be render. One of which can be a list of strings:

public class InnerBean implements  Serializable {

// Type of component
public static final String TEXT = "text";
public static final String TEXTLIST = "textlist";

private String label;
private String type;  // If TEXT, use value; if TEXTLIST, use list.
private String value;
private List<String> list = new ArrayList<String>();

public InnerBean() {
}

public void textListListener(AjaxBehaviorEvent event) {
    System.out.println("Listener called");
    System.out.println("       Source: " + event.getSource().toString());
    System.out.println("        Value: " + ((UIInput)event.getSource()).getValue());
    System.out.println("         List: " + list.toString());
    System.out.println("        Event: " + event.toString());

}

//
// Setters and getters
//

public String getLabel() {
    return label;
}

public void setLabel(String label) {
    this.label = label;
}

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

public String getValue() {
    return value;
}

public void setValue(String value) {
    this.value = value;
}

public List<String> getList() {
    return list;
}

public void setList(List<String> list) {
    this.list = list;
}

}

0

There are 0 best solutions below