我在JSF 2应用程序中使用Primefaces。我有<p:dataTable>
,而不是选择行,我希望用户能够直接对各行执行各种操作。为此,我在最后一栏中有几个<p:commandLink>
。
我的问题:如何将行ID传递给命令链接启动的操作,以便我知道要对哪一行进行操作?我尝试使用<f:attribute>
:
<p:dataTable value="#{bean.items}" var="item">
...
<p:column>
<p:commandLink actionListener="#{bean.insert}" value="insert">
<f:attribute name="id" value="#{item.id}" />
</p:commandLink>
</p:column>
</p:dataTable>
但它总是产生0 - 显然,当呈现属性时,行变量f
不可用(当我使用固定值时它会起作用)。
任何人都有替代解决方案吗?
答案 0 :(得分:211)
至于原因,<f:attribute>
特定于组件本身(在视图构建时填充),而不是迭代行(在视图渲染时填充)。
有几种方法可以达到这个要求。
请改用<f:param>
。它添加了一个请求参数。
<h:commandLink action="#{bean.insert}" value="insert">
<f:param name="id" value="#{item.id}" />
</h:commandLink>
如果您的bean是请求作用域,请让JSF按@ManagedProperty
@ManagedProperty(value="#{param.id}")
private Long id; // +setter
或者,如果您的bean具有更广泛的范围,或者您想要更精细的验证/转换,请在目标视图上使用<f:viewParam>
,另请参阅f:viewParam vs @ManagedProperty:
<f:viewParam name="id" value="#{bean.id}" required="true" />
无论哪种方式,这都具有以下优点:对于表单提交,不一定需要保留数据模型(对于您的bean是请求作用域的情况)。
请改用<f:setPropertyActionListener>
。优点是当bean具有比请求范围更广的范围时,这消除了访问请求参数映射的需要。
<h:commandLink action="#{bean.insert}" value="insert">
<f:setPropertyActionListener target="#{bean.id}" value="#{item.id}" />
</h:commandLink>
与
结合使用private Long id; // +setter
它只能由属性id
在操作方法中使用。这只需要为表单提交请求保留datamodel。最好是通过@ViewScoped
将bean放在视图范围内。
如果您的servletcontainer支持Servlet 3.0 / EL 2.2,那么只需将其作为方法参数传递。这还要求为表单提交请求保留datamodel。最好是通过@ViewScoped
将bean放在视图范围内。
<h:commandLink action="#{bean.insert(item.id)}" value="insert" />
结合:
public void insert(Long id) {
// ...
}
您甚至可以传递整个项目对象:
<h:commandLink action="#{bean.insert(item)}" value="insert" />
使用:
public void insert(Item item) {
// ...
}
在Servlet 2.5容器上,如果您提供支持此功能的EL实现(如JBoss EL),也可以这样做。有关配置详细信息,请参阅this answer。
将数据表值绑定到DataModel<E>
,而不是将其包装。
<h:dataTable value="#{bean.model}" var="item">
与
private transient DataModel<Item> model;
public DataModel<Item> getModel() {
if (model == null) {
model = new ListDataModel<Item>(items);
}
return model;
}
(使其transient
并在getter中实例化它是强制性的,因为DataModel
未实现Serializable
,因此在视图或会话范围的bean上使用它时是必需的})
然后,您将能够通过DataModel#getRowData()
访问当前行而不传递任何内容(JSF根据单击的命令链接/按钮的请求参数名称确定行)。
public void insert() {
Item item = model.getRowData();
Long id = item.getId();
// ...
}
这还要求为表单提交请求保留datamodel。最好是通过@ViewScoped
将bean放在视图范围内。
您可以使用Application#evaluateExpressionGet()
以编程方式评估当前#{item}
。
public void insert() {
FacesContext context = FacesContext.getCurrentInstance();
Item item = context.getApplication().evaluateExpressionGet(context, "#{item}", Item.class);
Long id = item.getId();
// ...
}
选择哪种方式取决于功能要求以及这一方面是否为其他目的提供了更多优势。我个人会继续使用#3,或者当你想支持servlet 2.5容器时,#2。
答案 1 :(得分:11)
在JSF 1.2中,这是由<f:setPropertyActionListener>
(在命令组件中)完成的。在JSF 2.0(确切地说是EL 2.2,感谢BalusC),可以这样做:action="${filterList.insert(f.id)}
答案 2 :(得分:10)
在我的视图页面中:
<p:dataTable ...>
<p:column>
<p:commandLink actionListener="#{inquirySOController.viewDetail}"
process="@this" update=":mainform:dialog_content"
oncomplete="dlg2.show()">
<h:graphicImage library="images" name="view.png"/>
<f:param name="trxNo" value="#{item.map['trxNo']}"/>
</p:commandLink>
</p:column>
</p:dataTable>
支持豆
public void viewDetail(ActionEvent e) {
String trxNo = getFacesContext().getRequestParameterMap().get("trxNo");
for (DTO item : list) {
if (item.get("trxNo").toString().equals(trxNo)) {
System.out.println(trxNo);
setSelectedItem(item);
break;
}
}
}
答案 3 :(得分:-1)
感谢this site by Mkyong,实际为我们传递参数的唯一解决方案是
<h:commandLink action="#{user.editAction}">
<f:param name="myId" value="#{param.id}" />
</h:commandLink>
与
public String editAction() {
Map<String,String> params =
FacesContext.getExternalContext().getRequestParameterMap();
String idString = params.get("myId");
long id = Long.parseLong(idString);
...
}
从技术上讲,您无法直接传递给方法本身,而是传递给JSF request parameter map
。