<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<>();

无论采用哪种方法,在操作方法中,只需遍历它即可将它们全部收集起来。