JSF& ui:repeat-将对象添加到购物车的问题 [英] JSF & ui:repeat - issue with adding an object to cart

查看:131
本文介绍了JSF& ui:repeat-将对象添加到购物车的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

再一次,我用Java Server Faces编写的Pizza-Search-Programm需要一些帮助.

Once again I need some help with my pizza-search-programm I have written with Java Server Faces.

程序: 用户可以通过输入表单来搜索披萨.用户可以决定是否搜索披萨名称,披萨ID或其他指定条件,因此可以进行过滤搜索.该程序将生成一个SQL查询,该查询返回披萨对象并将其存储到对象列表中. JSF页面通过对ui:repeat标签进行迭代来显示比萨饼对象的列表.显示比萨饼名称,比萨饼ID,可用大小(显示为单选按钮)和可能的数量列表.对于每个显示的比萨饼对象,都有一个添加到购物车按钮",用于在所选大小和数量的参数化值下将比萨饼添加到购物车中.

The program: A user can search for pizzas by entering a form. A filtered search is possible as the user can decide whether he searches for a pizza name, a pizza id or other specified criteria. The program will generate a SQL query which returns pizza objects and stores it into a list of objects. A JSF page displays the list of pizza objects by iterating them through a ui:repeat tag. Pizza name, pizza ID, available sizes (displayed as radio buttons) and a list of possible quantities are displayed. For each displayed pizza object there is an "add-to-cart-button", to add the pizza to the shopping cart under the parameterized values of the chosen size and quantity.

问题: 几乎所有内容都能正确显示.但是,当将比萨饼添加到购物车中时,会发生错误.如果用户搜索特定的披萨,则将披萨ID,所选大小和所选数量提交到购物车方法中不会有任何问题.但是,如果列表中包含多个比萨饼对象,则只需提交正确的比萨饼ID,所选大小和数量的正确值,就可以将最后一个比萨饼正确地添加到购物车中.如果用户尝试将一个上面的比萨饼放到他的购物车中,则将采用先前提交的所选大小和数量,前提是之前已经成功执行了添加到购物车操作".如果不为0,则无论用户选择什么尺寸和数量,都将提交.

The problem: Almost everything is displayed correctly. But when it comes to add a pizza to the cart, errors will occur. If the user searches for a specific pizza there will be no problems by submitting the pizza ID, the chosen size and the chosen quantity to the add-to-cart-method. But when the list comprises more than only one pizza object, only the last pizza can be added to the cart correctly by submitting the right values of pizza ID, chosen size and chosen quantity. If the user tries to put one of the upper pizzas to his cart, the previous submitted size and quantity chosen will be taken, provided that there was already an successfully executed "add-to-cart-action" before. If not 0 will be submitted, no matter what the user choses for size and quantity.

示例: 用户搜索披萨香肠".他将其中2个尺寸为40的购物车添加到了购物车中. (chosenPizzaID:1; selectedSize:40; selectedQuantity 2).一切都正确执行.但是之后,用户将搜索所有披萨.他想添加显示的列表中的第一个披萨.此披萨仅提供30尺寸.他从30"的披萨中选择了3个,然后单击添加到购物车按钮".该程序将以前的参数用于selectedSize和selectedQuantity(choenSize:40; selectedQuantity:2).

Example: User searches for "pizza salami". He adds 2 of them in size 40" to his cart. (chosenPizzaID: 1; chosenSize: 40; chosenQuantity 2). Everything is executed correctly. But after that the user searches for all pizzas. He wants to add the first pizza of the displayed list. This pizza is only available in size 30". He chose 3 of that pizza in size 30" and clicks "add-to-cart-button". The program takes the previous parameters for chosenSize and chosenQuantity (chosenSize: 40; chosenQuantity: 2).

PizzaSearch的代码段:

@ManagedBean
@SessionScoped
public class PizzaSearch {

   // variables in order to submit the search criteria
   private List<PizzaObject> results = new ArrayList<PizzaObject>();

   // methods to generate the search
   // each search result will fill/replace the list of pizza objects 'results'

   // getter and setter methods

}

PizzaResult的代码段:

@ManagedBean
@SessionScoped
public class PizzaResult {

   // injection of PizzaSearch
   @ManagedProperty(value="#{pizzaSearch}")
   private PizzaSearch pizzaSearch;

   // variables
   private List<PizzaObject> results;
   private int _chosenSize;
   private int _chosenQuantity;

   @PostConstruct
   public void initResults() {
      this.results = pizzaSearch.getResults();
   }

   // method to add the pizza object to the cart
   // a simple text output for testings
   public void addToCart(int chosenPizzaID) {
      System.out.println("chosen pizza ID: " + chosenPizzaID);
      System.out.println("chosen size:     " + _chosenSize);
      System.out.println("chosen quantity: " + _chosenQuantity);
   }

   // getter and setter methods
}

JSF输出页面的代码段

<ui:repeat var="result" value="#{pizzaResult.results}">
   <h:form>
      <ul>
         <li><p>Name: #{result.pizza.name}</p></li>
         <li><p>ID: #{result.pizza.pizzaID}</p></li>
         <li>
            <p>Toppings:</p>
            <ui:repeat var="topping" value="#{result.toppingList}">
               <p>#{topping.toppingName}</p>
            </ui:repeat>
         </li>
         <li>
            <p>Sizes:</p>
            <h:selectOneRadio id="chosenSize" value="#{pizzaResult.chosenSize}">
               <f:selectItems value="#{result.sizeList} var="size" itemLabel="#{size.diameter}" itemValue="#{size.sizeID}"/>
            </h:selectOneRadio>
         </li>
         <li>
            <p>Quantity:</p>
            <h:selectOneListbox id="chosenQuantity" value="#{pizzaResult.chosenQuantity}" size="1">
               <f:selectItem id="quantity1" itemLabel="1x" itemValue="1">
               <f:selectItem id="quantity2" itemLabel="2x" itemValue="2">
            </h:selectOneListbox>
         </li>
         <li>
            <h:commandButton value="add to cart" action="#{pizzaResult.addToCart(result.pizza.pizzaID)}"/>
         </li>
      </ul>
   </h:form>
</ui:repeat>

我感觉问题将由变量selectedSize和selectedQuantity调用.但是我不知道如何解决这个问题.我希望你能以某种方式帮助我.谢谢!

I have the feeling that the problem will be invoked by the variables chosenSize and chosenQuantity. But I don't have a clue of how to solve that problem. I hope you could help me somehow. Thanks!

推荐答案

我假设您使用Mojarra-JSF的参考实现.

I assume that you use Mojarra - reference implementation of JSF.

由于此答案中所述的Mojarra中的错误,原始代码无法正常工作.简而言之,ui:repeat不会保持其行的状态.

Original code does not work because of bug in Mojarra described in this answer. In short ui:repeat does not maintain state of its rows.

要使其正常工作,您必须:

In order to get it working you have to either:

  1. 切换到该代码可在其中运行的另一种实现(例如Apache MyFaces)(请参见该答案中的建议:
  1. switch to another implementation like Apache MyFaces where this code works (see my implementation)
  2. or move form outside the ui:repeat
  3. as suggested in that answer:

使用其他迭代组件(例如<c:forEach><h:dataTable><t:dataList><p:dataList>等)

但是,仅将表单移到ui:repeat之外,如@ user2314868所示,是行不通的.这是因为所有字段都是从表单中发布的.结果,每个h:selectOneRadio在更新模型值阶段都更新#{pizzaResult.chosenSize}.因此,在调用应用程序"阶段只有最后更新是可见的.对于#{pizzaResult.chosenQuantity}类似.

However, simply moving form outside the ui:repeat like @user2314868 suggested does not work. It is because all fields are posted from the form. As a result each h:selectOneRadio updates #{pizzaResult.chosenSize} during Update Model Values phase. Therefore only last update will be visible in Invoke Application phase. Similarly for #{pizzaResult.chosenQuantity}.

为了使其正常工作,我建议用值数组替换单个值(如selectedSize).比我们可以利用ui:repeat的状态变量的index属性.

In order to get it working I propose to replace single value like chosenSize with array of values. Than we can take advantage index property of status variable of ui:repeat.

<h:form id="pizzasForm">
    <ui:repeat var="result" value="#{pizzaResult.results}" varStatus="loop">

        <ul>
            <li><p>Name: #{result.pizza.name}</p></li>
            <li><p>ID: #{result.pizza.pizzaID}</p></li>
            <li>
                <p>Sizes:</p> <h:selectOneRadio id="chosenSize"
                    value="#{pizzaResult.chosenSize[loop.index]}">
                    <f:selectItems value="#{result.sizeList}" var="size"
                        itemLabel="#{size.diameter}" itemValue="#{size.sizeID}" />
                </h:selectOneRadio>
            </li>
            <li>
                <p>Quantity:</p> <h:selectOneListbox id="chosenQuantity"
                    value="#{pizzaResult.chosenQuantity[loop.index]}" size="1">
                    <f:selectItem id="quantity1" itemLabel="1x" itemValue="1" />
                    <f:selectItem id="quantity2" itemLabel="2x" itemValue="2" />
                </h:selectOneListbox>
            </li>
            <li><h:commandButton value="add to cart"
                    action="#{pizzaResult.addToCart(loop.index)}"/></li>
        </ul>

    </ui:repeat>
</h:form>

PizzaResult中的更改:

@ManagedBean
@SessionScoped
public class PizzaResult {

    // injection of PizzaSearch
    @ManagedProperty(value = "#{pizzaSearch}")
    private PizzaSearch pizzaSearch;

    // variables
    private List<PizzaObject> results;
    private int[] _chosenSize;
    private int[] _chosenQuantity;

    @PostConstruct
    public void initResults() {
        this.setResults(getPizzaSearch().getResults());
        int size = this.getResults().size();
        this._chosenSize = new int[size];
        this._chosenQuantity = new int[size];
    }

    // method to add the pizza object to the cart
    // a simple text output for testings
    public void addToCart(int index) {
        System.out.println("chosen pizza ID: " + results.get(index).getPizza().getPizzaID());
        System.out.println("chosen size:     " + getChosenSize()[index]);
        System.out.println("chosen quantity: " + getChosenQuantity()[index]);
    }
...

完整的示例可以在此处

这篇关于JSF&amp; ui:repeat-将对象添加到购物车的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆