我正在尝试使用JSF 2.2和PrimeFaces 4.0创建可更新的GUI。我的问题是模型已更新,但视图不是。
这是我的示例页面。它只有一个按钮,可以让两个面板改变它们的位置:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui">
<h:head/>
<h:body>
<h:form>
<p:panelGrid id="grid">
<p:row>
<p:column id="slot1" style="width: 100px; height: 100px">
<p:panel id="panel1" binding="#{test.panel1}" style="width: 100px; height: 100px"/>
</p:column>
<p:column id="slot2" style="width: 100px; height: 100px">
<p:panel id="panel2" binding="#{test.panel2}" style="width: 100px; height: 100px"/>
</p:column>
</p:row>
</p:panelGrid>
<p:commandButton id="button2" value="Switch Panels">
<p:ajax listener="#{test.onSwitchPanels(event)}" update="grid"/>
</p:commandButton>
</h:form>
</h:body>
</html>
Java类:
@ManagedBean
@SessionScoped
public class Test {
Panel panel1 = new Panel();
Panel panel2 = new Panel();
public Test() {
panel1.setHeader("Panel 1");
panel2.setHeader("Panel 2");
}
public Panel getPanel1() {
return panel1;
}
public void setPanel1(Panel panel) {
this.panel1 = panel;
}
public Panel getPanel2() {
return panel2;
}
public void setPanel2(Panel panel) {
this.panel2 = panel;
}
public void onSwitchPanels(ActionEvent event) {
Panel tmp = panel1;
panel1 = panel2;
panel2 = tmp;
}
}
调试显示,当单击按钮时,onSwitchPanels()
之后使用正确的新值调用getter和setter。
但正如我写的那样,视图没有更新。只有在手动页面刷新或下一次单击后才会发生这种情况(当然,这会将模型设置回原始状态,但会显示切换的面板)。
我已经尝试了update="@form"
和update="slot1 slot2"
但没有运气......
答案 0 :(得分:2)
这段代码老实说是WTF。将UI组件实例绑定到会话范围的bean是一个麻烦的方法。 UI组件实例即请求范围。
即使您使用了请求范围的bean,这也无法在不重建视图的情况下工作。在构建视图期间创建UI组件树。在构建视图之后,您正在操作组件引用,并期望更改在UI组件树中神奇地反映出来。这不是真的。只会反映他们的属性(因此,当您执行panel1.setHeader(panel2.getHeader())
时,反之亦然,那么它就会工作&#34;。
不清楚为什么你在这个方向思考。通常,您应该动态操作模型,而不是视图(UI组件不代表模型,它们代表视图;使模型/控制器的属性不会神奇地使其成为模型)。最直接的方法之一是拥有一个实体列表并将它们呈现在动态<p:dataGrid>
中而不是硬编码<p:panelGrid>
中,从而根据当前迭代的模型项动态设置所需的组件属性。
E.g。这个
<h:form>
<p:dataGrid value="#{bean.items}" var="item" columns="2">
<p:column><p:panel header="#{item.header}" /></p:column>
</p:dataGrid>
<p:commandButton value="swap" action="#{bean.swap}" update="grid" />
</h:form>
在@ViewScoped
(!)bean中使用它:
private List<Item> items; // +getter
@PostConstruct
public void init() {
items = new ArrayList<>();
items.add(new Item("Panel 1"));
items.add(new Item("Panel 2"));
}
public void swap() {
items.add(items.remove(0)); // Note: works only if you've only 2 items ;)
}
Item
类只是一个具有header
属性的javabean。平均IDE可以自动生成整个类。
答案 1 :(得分:0)
我的JSF / PF有点生疏,但你试过了吗?
update="panel1 panel2"
要尝试的另一件事是使用
actionListener"#{test.onSwitchPanels}"
而不是
listener="#{test.onSwitchPanels(event)}"
答案 2 :(得分:0)
为什么不从onSwitchPanels()方法中删除'event'参数?你没有以任何方式使用它。你可以通过
解雇它<p:commandButton id="button2" value="Switch Panels" action="#{test.onSwitchPanels}" update="grid" />
答案 3 :(得分:0)
我找到了采用此示例的解决方案:http://www.wobblycogs.co.uk/index.php/computing/jee/70-dynamic-dashboard-with-primefaces-part-2
重点是以编程方式创建组件。在JSF页面中,我只需编写类似<p:panelGrid id="grid" binding="#{gridBacker.grid}"/>
的内容,并使用bean使用Application.createComponent()
创建行,列和面板。事件发生后,小组将再次加入。
当然,BalusC是正确的,必须在模型中进行。