我目前正试图通过添加/删除primefaces p:commandButton
来做一个简单的输入列表。
我在Glassfish 4.1.1上使用PrimeFaces 6.2和Mojarra 2.2.12。
example bean.Java
package /* myPackage */;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javafx.util.Pair;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
@Named(value = "exampleBean")
@SessionScoped
public class ExampleBean implements Serializable {
private List<Pair<Integer, Integer>> list;
@PostConstruct
public void init() {
list = new ArrayList<>();
addNewItem();
}
public void addNewItem() {
list.add(new Pair<>(1, 300));
}
public List<Pair<Integer, Integer>> getList() {
return list;
}
public void setList(List<Pair<Integer, Integer>> list) {
this.list = list;
}
}
example.xhtml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:jsf="http://xmlns.jcp.org/jsf">
<h:head>
<title>Example</title>
<meta charset="utf-8" />
</h:head>
<h:body>
<h:form id="example-form">
<div jsf:id="example-container">
<ui:repeat value="#{exampleBean.list}" var="item" varStatus="status">
<div>
<p:inputText value="#{item.key}" />
<p:inputText value="#{item.value}" />
<p:commandButton
value="Delete"
actionListener="#{exampleBean.list.remove(item)}"
process="@this"
update="example-form:example-container"
rendered="#{!status.first}" />
<p:commandButton
value="Add"
actionListener="#{exampleBean.addNewItem()}"
process="@this"
update="example-form:example-container"
rendered="#{status.first}" />
</div>
</ui:repeat>
</div>
</h:form>
</h:body>
</html>
使用我的每个rendered
的p:commandButton
属性,我想只在第一个项目上显示添加按钮,并在除第一个项目之外的所有项目上显示删除按钮(使其不可删除)。
我的问题是,在添加按钮上使用rendered="#{status.first}"
会使整个事情无法正常工作。
<p:commandButton ... rendered="#{status.last}" /> <!-- actionListener called -->
<p:commandButton ... rendered="#{true}" /> <!-- actionListener called -->
<p:commandButton ... rendered="#{status.first}" /> <!-- actionListener NOT called -->
使用rendered="#{status.first}"
,单击按钮不会调用actionListener
但会触发update
。
我不知道在第一个项目中显示它而不是在其他项目中或在最后一个项目中显示它会有什么变化。
我认为这与<ui:repeat>
标志和命令按钮的唯一ID的生成有关。视图可能会混淆。添加其他按钮时生成的ID会发生变化。此外,引入呈现的属性也会改变组件处理方式。
所以要解决这个问题,我认为你需要重新处理ui:repeat
组件和命令按钮才能获得有效的动作URL。解决方案很简单 - 删除process="@this"
。
我用一个有效的解决方案调整了你的例子(该例子使用了Lombok);
@Data @Named @ViewScoped
public class ExampleBean implements Serializable {
private List<IntegerPair> list;
@PostConstruct
private void init() {
list = new ArrayList<>();
addNewItem();
}
public void addNewItem() {
list.add(new IntegerPair(1, 300));
}
@Data
@AllArgsConstructor
public class IntegerPair {
private int key, value;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui"
xmlns:jsf="http://xmlns.jcp.org/jsf">
<h:head>
<title>Example</title>
<meta charset="utf-8" />
</h:head>
<h:body>
Test!
<h:form id="example-form">
<div jsf:id="example-container">
<ui:repeat value="#{exampleBean.list}" var="item" varStatus="status">
<div>
<p:inputText value="#{item.key}" />
<p:inputText value="#{item.value}" />
<p:commandButton
value="Delete"
actionListener="#{exampleBean.list.remove(item)}"
update="example-form:example-container"
rendered="#{!status.first}" />
<p:commandButton
value="Add"
actionListener="#{exampleBean.addNewItem}"
update="example-form:example-container"
rendered="#{status.first}" />
</div>
</ui:repeat>
</div>
</h:form>
</h:body>
</html>
注意IntegerPair
类?我不得不介绍这个,因为JavaFX中定义的Pair<>
类没有可写的键属性 - 当JSF处理输入组件的支持bean值时,JSF需要可写属性。
坦率地说,因为您面临的问题源于<ui:repeat>
组件/标签,在您的命令按钮上执行process="example-form:example-container"
也应该正常工作 - 只需确保<ui:repeat>
包含在处理阶段。