What is the correct way to implement this scenario, without resorting to a View or Session scoped bean? Surely there must be a way to just POST the form and delete the appropriate record without having to waste time regenerating the list of records
Sorry, there's no way. At least not when using a standard <h:commandButton>
inside a standard <h:dataTable>
. This is the consequence of the stateful nature of JSF. JSF just wants to ensure that the view is exactly the same during processing the postback as it was during generating the HTML output.
This is part of JSF's safeguard against tampered requests wherein the enduser/hacker can manipulate the request parameters in such way that it could do hazardful things, e.g. changing the ID of entry to delete, or bypassing the check on rendered
attribute, etc. All those things on which you would/should do additional pre-validation anyway if JSF didn't do that for you and are easily overlooked by starters (they would then blame JSF for being insecure instead of themselves). See also Why JSF saves the state of UI components on server? and commandButton/commandLink/ajax action/listener method not invoked or input value not updated.
In case of <h:commandButton>
inside <h:dataTable>
, JSF simply needs to have the data model available during the apply request values phase, so that it can iterate over the <h:dataTable>
in the component tree in order to find the pressed button and queue the action event. If there's no datamodel, then it can't find the pressed button and the action event won't be queued. Normally, this is to be solved by placing the managed bean in the JSF view scope. See also How to choose the right bean scope?
In case of request scoped beans, the <f:viewParam>
is indeed not the right tool for the job of preserving the data model before apply request values phase takes place. You need to do the job in a @PostConstruct
annotated method instead. The request parameters can in case of JSF managed beans be injected via @ManagedProperty
. See also ViewParam vs @ManagedProperty(value = "#{param.id}"). In case of CDI or Spring managed beans, there's no standard annotation available to inject a HTTP request parameter as a bean property. For CDI, the JSF utility library OmniFaces has a @Param
for the very purpose. See also OmniFaces @Param
showcase. For Spring, you'd need to homegrow it yourself. I, as non-Spring-user have however no idea how to do that. Google also doesn't seem to reveal much.
Alternatively, you can also just put the bean in the view scope by @ViewScoped
. It'll then live as long as you postback to the same view. JSF 2.2 has a CDI compatible annotation for that in javax.faces.view
package. The one in javax.faces.bean
package is the old JSF 2.0/2.1 annotation for @ManagedBean
. Spring has no annotation out the box for this as that would otherwise put a dependency on JSF API. You'd need to homegrow it yourself. Google shows several examples.