I'm using Primefaces in a JSF 2 application. I have a <p:dataTable>
, and instead of selecting rows, I want the user to be able to directly execute various actions on individual rows. For that, I have several <p:commandLink>
s in the last column.
My problem: how can I pass a row ID to the action started by the command link so that I know which row to act on? I tried using an <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>
But it always yields 0 - apparently the row variable f
is not available when the attribute is rendered (it works when I use a fixed value).
Anyone has an alternative solution?
In JSF 1.2 this was done by
<f:setPropertyActionListener>
(within the command component). In JSF 2.0 (EL 2.2 to be precise, thanks to BalusC) it's possible to do it like this:action="${filterList.insert(f.id)}
In my view page:
backing bean
Thanks to this site by Mkyong, the only solution that actually worked for us to pass a parameter was this
with
Technically, that you cannot pass to the method itself directly, but to the
JSF request parameter map
.As to the cause, the
<f:attribute>
is specific to the component itself (populated during view build time), not to the iterated row (populated during view render time).There are several ways to achieve the requirement.
Use
<f:param>
instead. It adds a request parameter.If your bean is request scoped, let JSF set it by
@ManagedProperty
Or if your bean has a broader scope or if you want more fine grained validation/conversion, use
<f:viewParam>
on the target view, see also f:viewParam vs @ManagedProperty:Either way, this has the advantage that the datamodel doesn't necessarily need to be preserved for the form submit (for the case that your bean is request scoped).
Use
<f:setPropertyActionListener>
instead. The advantage is that this removes the need for accessing the request parameter map when the bean has a broader scope than the request scope.In combination with
It'll be just available by property
id
in action method. This only requires that the datamodel is preserved for the form submit request. Best is to put the bean in the view scope by@ViewScoped
.If your servletcontainer supports Servlet 3.0 / EL 2.2, then just pass it as method argument. This also requires that the datamodel is preserved for the form submit request. Best is to put the bean in the view scope by
@ViewScoped
.In combination with:
You can even pass the entire item object:
with:
On Servlet 2.5 containers, this is also possible if you supply an EL implementation which supports this, like as JBoss EL. For configuration detail, see this answer.
Bind the datatable value to
DataModel<E>
instead which in turn wraps the items.with
(making it
transient
and lazily instantiating it in the getter is mandatory when you're using this on a view or session scoped bean sinceDataModel
doesn't implementSerializable
)Then you'll be able to access the current row by
DataModel#getRowData()
without passing anything around (JSF determines the row based on the request parameter name of the clicked command link/button).This also requires that the datamodel is preserved for the form submit request. Best is to put the bean in the view scope by
@ViewScoped
.You can use
Application#evaluateExpressionGet()
to programmatically evaluate the current#{item}
.Which way to choose depends on the functional requirements and whether the one or the other offers more advantages for other purposes. I personally would go ahead with #3 or, when you'd like to support servlet 2.5 containers as well, with #2.