Reputation: 45
I have a <h:dataTable>
displaying a product catalog in Proudcts.xhtml
:
<h:form name="ViewProductsManagedBean">
<h:dataTable var="product" value="#{ViewProductsManagedBean.productsList}">
<h:column>
<h:outputText value="#{product.productid}" />
</h:column>
<h:column>
<h:outputText value="#{product.itemcode}" />
</h:column>
<h:column>
<h:outputText value="#{product.itemdescription}" />
</h:column>
<h:column>
<h:outputText value="#{product.unitprice}" />
</h:column>
<h:column>
<h:selectOneMenu value="#{ViewProductsManagedBean.quantityPurchased}" required="true">
<f:selectItem itemValue="1" itemLabel="1" />
<f:selectItem itemValue="2" itemLabel="2" />
<f:selectItem itemValue="3" itemLabel="3" />
<f:selectItem itemValue="4" itemLabel="4" />
<f:selectItem itemValue="5" itemLabel="5"/>
</h:selectOneMenu>
</h:column>
<h:column>
<h:commandButton action="#{ViewProductsManagedBean.addItemToCart(product)}" value="Add to basket" />
</h:column>
</h:dataTable>
</h:form>
With this managed bean:
@ManagedBean(name="ViewProductsManagedBean")
@SessionScoped
public class ViewProductsManagedBean {
private double unitprice;
private String itemdescription;
private String itemcode;
private int quantityPurchased;
private String result;
@EJB
ProductLocal productFacadeBean;
@EJB
CartFacade cartFunctions;
private List<ProductEntity> productsList = new ArrayList<>();
private List<StockEntity> stocksList = new ArrayList<>();
private ProductEntity product;
@PostConstruct
private void init(){
setProductsList();
product = new ProductEntity();
}
public void addItemToCart(ProductEntity product) {
int quantity=this.quantityPurchased;
cartFunctions.addItemToCart(product, quantity);
System.out.println(product.toString());
}
// getters+setters
}
The problem is with the <h:selectOneMenu>
to select the quantity. No matter what value is selected, the managed bean always receives a value of 1 for quantity, EXCEPT when the quantity is changed in the last item of the product catalog, in which case the quantity for ALL the items change to the value selected for the last item in the catalog, and the correct quantity is sent to the managed bean.
How is this caused and how can I solve it?
Upvotes: 1
Views: 1370
Reputation: 1108632
Here,
<h:selectOneMenu value="#{ViewProductsManagedBean.quantityPurchased}">
You're basically binding the value of all input fields to one and same bean property. So, when the form gets submitted, every iteration of the table will override the bean property everytime with the submitted value of the current iteration round until you end up getting the value of the last row. If you have placed a debug breakpoint on the setter method, you should have noticed that.
This is definitely not right. You need to associate the input value with the currently iterated object. The simplest but naive way would be to directly associate it with the object:
<h:selectOneMenu value="#{product.quantityPurchased}">
This only tight-couples in your particular case the "quantity" model with the "product" model. It's functionally reasonable to keep them separated. A more proper solution is then to map the input value with currently iterated object as key (provided that the object has a proper equals()
and hashCode()
implementation, obviously):
<h:selectOneMenu value="#{ViewProductsManagedBean.quantitiesPurchased[product]}" converter="javax.faces.Integer">
With:
private Map<ProductEntity, Integer> quantitiesPurchased = new HashMap<>();
Regardless of the approach, in the action method, just iterate over it to collect them all.
Upvotes: 3
Reputation: 61
Agree with Matt. Change your behaviour to be Ajax bt adding and set to execute the @this and quantity and render the cart. That way it will only process that row, not the whole table.
Also I would change the action yo actionlistener.
Upvotes: -1
Reputation: 30025
Each line of your h:datatable
references the same variable ViewProductsManagedBean.quantityPurchased
. If the form is submitted, the value of ViewProductsManagedBean.quantityPurchased
will be set for each line again and again. That's why the value of the last row defines the final state of quantityPurchased
and this is the value you get in your method.
Upvotes: 1