我是JSF2的新手。使用JPA,我在菜肴和配料之间有双向的OneToMany关系。
该应用程序有一个视图,允许添加至少一种成分的菜肴,用户可以通过Javascript添加其他成分,这基本上只是复制代表成分的HTML元素。
截图让我更清楚我的意思 - 最初只有一种成分,但用户可以通过点击相应的按钮一次添加/删除一种成分:
我刚刚在辅助bean中的@PostConstruct中创建的初始成分:
@Named
@Produces
private Dish addDish;
@PostConstruct
public void init() {
this.addDish = new Dish();
final Ingredient ingredient = new Ingredient();
ingredient.setDish(this.addDish);
this.addDish.getIngredients().add(ingredient);
}
public String add() {
databaseService.persist(addDish);
return OUTCOME;
}
提交含有初始成分的菜肴工作正常,它会被正确地保存到数据库中。
但现在我想知道我怎么知道用户提交的表格中实际有多少成分,然后我会在哪里创建适当数量的Ingredient实例并将它们添加到Dish实例?
答案 0 :(得分:1)
为了提供您想要的快速示例,我将为您提供一些基本代码。假设您想要创建菜肴本身和所有相关成分,您应该在JPA中声明一对多关系并将级联模式设置为all
。这样,当您保存菜肴时,您将能够保存每种相关成分。
话虽如此,让我们使用JSF相关代码,它允许您添加 - 删除一个成分并保存菜:
<强> newDish.xhtml:强>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head />
<h:body>
<h:messages />
<h:form id="form" prependId="true">
<h:panelGrid columns="1">
Preparation:
<h:inputTextarea value="#{newDishBean.newDish.preparation}"
required="true" />
</h:panelGrid>
<h:dataTable value="#{newDishBean.newDish.ingredients}"
var="ingredient" id="ingredients">
<h:column>
<h:inputText value="#{ingredient.amount}" required="true" />
</h:column>
<h:column>
<h:inputText value="#{ingredient.unit}" required="true" />
</h:column>
<h:column>
<h:inputText value="#{ingredient.name}" required="true" />
</h:column>
</h:dataTable>
<h:commandButton value="Add Ingredient">
<!-- Sends the whole form (execute="@form") into the POST request in order to keep the model updated -->
<f:ajax listener="#{newDishBean.addIngredient}" render="ingredients"
execute="@form" />
</h:commandButton>
<h:commandButton value="Remove Ingredient">
<!-- Here we don't need to send extra info. Just the button component (@this) is executed -->
<f:ajax listener="#{newDishBean.removeIngredient}"
render="ingredients" />
</h:commandButton>
<!-- Non-ajax request. The whole form is sent to the server -->
<h:commandButton value="Create dish"
action="#{newDishBean.createDish}" />
</h:form>
</h:body>
</html>
<强> NewDishBean.java:强>
@ManagedBean
@ViewScoped
public class NewDishBean {
public class Dish {
private String preparation;
private List<Ingredient> ingredients = new ArrayList<Ingredient>();
public List<Ingredient> getIngredients() {
return ingredients;
}
public String getPreparation() {
return preparation;
}
public void setIngredients(List<Ingredient> ingredients) {
this.ingredients = ingredients;
}
public void setPreparation(String preparation) {
this.preparation = preparation;
}
@Override
public String toString() {
return "Dish [preparation=" + preparation + ", ingredients="
+ ingredients + "]";
}
}
public class Ingredient {
private Dish dish;
private int amount;
private String unit;
private String name;
public int getAmount() {
return amount;
}
public Dish getDish() {
return dish;
}
public String getName() {
return name;
}
public String getUnit() {
return unit;
}
public void setAmount(int amount) {
this.amount = amount;
}
public void setDish(Dish dish) {
this.dish = dish;
}
public void setName(String name) {
this.name = name;
}
public void setUnit(String unit) {
this.unit = unit;
}
@Override
public String toString() {
return "Ingredient [amount=" + amount + ", unit=" + unit
+ ", name=" + name + "]";
}
}
private Dish newDish = new Dish();
public void addIngredient() {
Ingredient i = new Ingredient();
i.setDish(newDish);
newDish.ingredients.add(i);
}
public void createDish() {
// Do your JPA stuff
System.out.println(newDish + " created!");
}
public Dish getNewDish() {
return newDish;
}
public void removeIngredient() {
if (!newDish.ingredients.isEmpty()) {
newDish.ingredients.remove(newDish.ingredients.size() - 1);
}
}
}
基本上你所做的就是在创建bean时创建一个新菜。每次点击“添加成分”时,都会在新菜中添加一种成分并显示在表中。
这是实现您想要的JSF标准方法。作为一个有状态框架,JSF倾向于为模型中的每个更改更新它的状态(可以保留在服务器端或客户端)。当然,你可以使用Javascript为表添加一行新成分,但这需要自己更新这个状态。
另见:
答案 1 :(得分:0)
我最终在我的问题中抛弃了这个方法,然后针对类似的问题找到了accepted answer建议的解决方案。
更新JSF生成的标记感觉有点蠢,使用AJAX的解决方案非常简单,似乎更像JSF方式。
唯一遗憾的是,对服务器的请求是针对可以完全在客户端完成的事情。
注意:如果您喜欢我,不希望AJAX呈现整个表单,只需要<div>
,即动态添加元素,将该部分包装在<h:panelGroup id="render-by-ajax" layout="block">
中。