0
votes

I have a page with a PrimeFaces Accordion containing a dataTable. Accordion Tabs and Table rows can be added dynamically with buttons. Now I observe strange things regarding data binding. I can see that my accordion tabs (which represent OrderProducts in Java) are bound to my bean and updated at any time. The dataTable rows are not always bound to their corresponding bean (OrderDestination) and therefore the data is not always updated after submitting. The first tab seems to work as expected, but in the second tab (if I add a second one) the binding does not work. Also I tried to add an empty OrderDestination to every new OrderProduct in the constructor (not visible in the code below). This default OrderDestination is never bound to the bean. Am I doing something wrong or can you spot any error or misunderstanding in the following code?

orderCreate.xhtml (simplified)

<h:form id="orderPlaceForm">    
    <p:accordionPanel id="productAccordion" value="#{orderCreateModel.orderProducts}" var="product">
        <p:tab>
            <h:dataTable var="item" value="#{product.orderDestinations}">
                <h:column>
                    <h:inputText value="#{item.totalWeightKg}">
                </h:column>
                <!-- other columns -->
            </h:dataTable>

            <!-- button to add another row -->
            <h:commandButton value="add dest" action="#{orderCreate.addDestination}">
                <f:param name="productId" value="#{product.uuid}" />
                <f:ajax render="productAccordion" execute="@this productAccordion"/>
            </h:commandButton>
        </p:tab>
    </p:accordionPanel>

    <!-- button to add another tab -->
    <h:commandButton value="add prod" action="#{orderCreate.addProduct}">
        <f:ajax render=":orderPlaceForm:productAccordion" execute="@this :orderPlaceForm:productAccordion"/>
    </h:commandButton>
</h:form>

OrderCreate.java

@ManagedBean
@RequestScoped
public class OrderCreate {

    @ManagedProperty(value="#{orderCreateModel}")
    private OrderCreateModel orderCreateModel;

    public void addProduct() {
        orderCreateModel.addProduct();
    }

    public void addDestination() {
        orderCreateModel.findProduct(prodId).addDestination(); //prodId from FacesContext
    }
}

OrderCreateModel.java

public class OrderCreateModel {
    private List<OrderProduct> orderProducts = new ArrayList();

    public void addProduct() {
        orderProducts.add(new OrderProduct());
    }

    public OrderProduct findProduct(UUID prodID) {
        //look in orderProducts for prodID
    }
}

OrderProduct.java

public class OrderProduct {
    private List<OrderDestination> orderDestinations = new ArrayList();

    public void addDestination() {
        orderDestinations.add(new OrderDestination());
    }
}

OrderDestination.java

public class OrderDestination {
    //POJO with some String fields
}
1
The more I try to understand this issue by myself, I get the feeling, that the problem has something to do with elements (OrderProducts or OrderDestinations) I create initially in code. When instantiating the initial OrderCreateModel I add one OrderProduct with one OrderDestination in it. This OrderDestination is not bound. When I add an additional OrderDestination using the buttons, the newly created OrderDestinations are bound... - Retolinho

1 Answers

0
votes

The solution is simple but not easy to find and understand: Using ServerFace elements (e.g. h:dataTable) within a Primeface element (p:accordionPanel) leads to unexpected and unpredictable behavior. As soon as I replace all ServerFace elements nested within Primeface's accordion panel with the corresponding Primeface elements (e.g. p:dataTable), everything works as expected.