<h:dataTable> 中的输入字段始终接收列表中最后一项的值
Input field in <h:dataTable> always receives value of last item in list
我有一个 <h:dataTable>
在 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>
使用这个托管 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
}
问题出在 <h:selectOneMenu>
到 select 的数量上。无论 selected 的值是什么,托管 bean 的数量值始终为 1,除非在产品目录的最后一项中更改了数量,在这种情况下,所有项目的数量都会更改为目录中最后一项的值 selected,并将正确的数量发送到托管 bean。
这是怎么造成的,我该如何解决?
您的 h:datatable
的每一行都引用同一个变量 ViewProductsManagedBean.quantityPurchased
。如果表单被提交,ViewProductsManagedBean.quantityPurchased
的值将被一次又一次地为每一行设置。这就是为什么最后一行的值定义了 quantityPurchased
的最终状态,这就是您在方法中获得的值。
同意马特的观点。将您的行为更改为 Ajax bt 添加并设置为执行 @this 和数量并呈现购物车。这样它只会处理该行,而不是整个 table。
另外,我会更改动作哟 actionlistener。
这里,
<h:selectOneMenu value="#{ViewProductsManagedBean.quantityPurchased}">
您基本上是将 所有 输入字段的值绑定到同一个 bean 属性。因此,当提交表单时,table 的每次迭代都会使用当前迭代轮次的提交值覆盖 bean 属性,直到您最终获得最后一行的值。如果您在 setter 方法上放置了调试断点,您应该已经注意到了。
这绝对不对。您需要将输入值与当前迭代的对象相关联。最简单但天真的方法是直接将它与对象相关联:
<h:selectOneMenu value="#{product.quantityPurchased}">
这仅在您的特定情况下紧密耦合 "quantity" 模型与 "product" 模型。将它们分开在功能上是合理的。一个更合适的解决方案是将输入值与当前迭代的对象映射为键(前提是该对象具有适当的 equals()
和 hashCode()
实现,显然):
<h:selectOneMenu value="#{ViewProductsManagedBean.quantitiesPurchased[product]}" converter="javax.faces.Integer">
有:
private Map<ProductEntity, Integer> quantitiesPurchased = new HashMap<>();
无论采用哪种方法,在操作方法中,只需遍历它即可将它们全部收集起来。
我有一个 <h:dataTable>
在 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>
使用这个托管 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
}
问题出在 <h:selectOneMenu>
到 select 的数量上。无论 selected 的值是什么,托管 bean 的数量值始终为 1,除非在产品目录的最后一项中更改了数量,在这种情况下,所有项目的数量都会更改为目录中最后一项的值 selected,并将正确的数量发送到托管 bean。
这是怎么造成的,我该如何解决?
您的 h:datatable
的每一行都引用同一个变量 ViewProductsManagedBean.quantityPurchased
。如果表单被提交,ViewProductsManagedBean.quantityPurchased
的值将被一次又一次地为每一行设置。这就是为什么最后一行的值定义了 quantityPurchased
的最终状态,这就是您在方法中获得的值。
同意马特的观点。将您的行为更改为 Ajax bt 添加并设置为执行 @this 和数量并呈现购物车。这样它只会处理该行,而不是整个 table。
另外,我会更改动作哟 actionlistener。
这里,
<h:selectOneMenu value="#{ViewProductsManagedBean.quantityPurchased}">
您基本上是将 所有 输入字段的值绑定到同一个 bean 属性。因此,当提交表单时,table 的每次迭代都会使用当前迭代轮次的提交值覆盖 bean 属性,直到您最终获得最后一行的值。如果您在 setter 方法上放置了调试断点,您应该已经注意到了。
这绝对不对。您需要将输入值与当前迭代的对象相关联。最简单但天真的方法是直接将它与对象相关联:
<h:selectOneMenu value="#{product.quantityPurchased}">
这仅在您的特定情况下紧密耦合 "quantity" 模型与 "product" 模型。将它们分开在功能上是合理的。一个更合适的解决方案是将输入值与当前迭代的对象映射为键(前提是该对象具有适当的 equals()
和 hashCode()
实现,显然):
<h:selectOneMenu value="#{ViewProductsManagedBean.quantitiesPurchased[product]}" converter="javax.faces.Integer">
有:
private Map<ProductEntity, Integer> quantitiesPurchased = new HashMap<>();
无论采用哪种方法,在操作方法中,只需遍历它即可将它们全部收集起来。