我再次需要一些帮助来完成我用Java Server Faces编写的披萨搜索程序。
程序:用户可以通过输入表单来搜索披萨。过滤搜索是可能的,因为用户可以决定是否搜索披萨名称、披萨id或其他指定条件。该程序将生成一个SQL查询,返回pizza对象并将其存储到对象列表中。JSF页面显示pizza对象的列表,方法是通过一个ui:repeat标签对它们进行迭代。显示披萨名称、披萨ID、可用尺寸(显示为单选按钮(和可能数量的列表。对于每个显示的披萨对象,都有一个"添加到购物车按钮",用于将披萨添加到所选尺寸和数量的参数化值下的购物车中。
问题:几乎所有内容都显示正确。但是,当要将披萨添加到购物车时,会出现错误。如果用户搜索特定的披萨,那么通过将披萨ID、所选尺寸和所选数量提交到添加到购物车的方法将不会出现问题。但是,当列表包含不止一个披萨对象时,通过提交正确的披萨ID值、选择的尺寸和选择的数量,只有最后一个披萨才能正确添加到购物车中。如果用户试图将上面的一个披萨放进他的购物车,那么将采用之前提交的所选尺寸和数量,前提是之前已经成功执行了"添加到购物车操作"。如果不是,无论用户选择什么尺寸和数量,都将提交0。
示例:用户搜索"披萨萨拉米"。他在手推车上加了两个40码的。(选择披萨ID:1;选择尺寸:40;选择数量2(。一切都执行正确。但在那之后,用户会搜索所有的披萨。他想添加显示列表中的第一个比萨饼。这个披萨只有30码。他选择了3个30码的披萨,然后点击"添加到购物车按钮"。程序采用chosenSize和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>
我有一种感觉,这个问题将由变量chosenSize和chosenQuantity调用。但我不知道如何解决那个问题。我希望你能以某种方式帮助我。谢谢
我假设您使用的是JSF的Mojarra参考实现。
由于Mojarra中的错误,原始代码无法工作。简而言之,ui:repeat不维护其行的状态。
为了让它发挥作用,你必须:
- 切换到另一个实现,如ApacheMyFaces,该代码在其中工作(请参阅我的实现(
- 或将表单移动到
ui:repeat
之外 - 如该回答中所建议的:
使用另一个迭代组件(例如
<c:forEach>
、<h:dataTable>
、<t:dataList>
、<p:dataList>
等(
然而,像@user2314868建议的那样,简单地将表单移动到ui:repeat
之外是行不通的。这是因为所有字段都是从表单中发布的。因此,每个h:selectOneRadio
都会在更新模型值阶段更新#{pizzaResult.chosenSize}
。因此,在调用应用程序阶段,只有最后一次更新才可见。与#{pizzaResult.chosenQuantity}
类似。
为了使它发挥作用,我建议用值数组来替换像chosenSize这样的单个值。然后我们可以利用CCD_ 11状态变量的CCD_。
<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]);
}
...
完整的工作示例可以在这里找到
要做的步骤:
步骤1:
Move the h:form outside the ui:repeat (In JSF)
步骤2:
Give some id to the form (In JSF)
步骤3:
update the form once add method exucuted
<h:commandButton value="add to cart" action="#{pizzaResult.addToCart(result.pizza.pizzaID)}" update="give form id name here"/>
第4步:
In addToCart() method, reset chosenPizzaID, _chosenSize and _chosenQuantity to 0
i.e
chosenPizzaID=0
_chosenSize=0
_chosenQuantity=0