The view:
<h:form ...
<p:dataTable value="#{myBean.list}" var="data" ...
<p:column ...
<h:commandButton action="#{controller.method(data.id)}" />
</p:column>
</p:dataTable>
</h:form>
The controller:
@ApplicationScoped
public class Controller {
public String method(final Long dataId) {
/* Do business */
return URL_WITH_REDIRECT;
}
}
The producer
(using the @ViewScoped
CDI annotation as described here)
@ApplicationScoped
public class Producer {
@Named @ViewScoped @Producer
public MyBean getMyBean() {
final MyBean bean = new MyBean();
bean.list = new ArrayList<Data>(); // where Data has a Long id field
/* Do business and populate list */
return bean;
}
}
The problem & its scenario
GET
the page- The bean is produced
- View is rendered
- Response sent to browser
- Click the button
- Data is
POST
ed to server - Phases 1-4 are executed without any issue, and that use
@ViewScoped
beans as expected - Phase 5:
controller.method
is called withdata.id
and accesses beans generated at 1.1 - Method returns redirect
String
- !! The producer is called again !! - we're still in APPLICATION_INVOCATION phase, but after the actual method call
- Data is
- Browser receives redirect
GET
next page ...
The half-"donkey" solution that works:
In short: on click, copy the id outside the datatable, and trigger a click on a submit button.
On the h:commandButton
inside the table column added :
onclick="$('input[id*=selectedDataId]').val('#{data.id}'); $('button[id*=callMethod]').trigger('click');"
Outside the table:
<h:inputHidden id="{selectedDataId}"binding="#{selectedDataId}"/>
<p:commandButton type="submit"
id="callMethod"
label="Hidden button"
action="#{controller.method(selectedDataId.value)}"/>
At the end it works, but I was not able to figure out what causes the first & base approach to reinitialize the view scoped bean. Looking at the stack trace (see below) it seems like it is rebuilding the rows.
Question:
Does anyone have an explanation, and maybe caveats to look out for regarding this issue?
Stack trace
Where: getPipelinecheckSearchResults
is the call for retrieving the list that backs the table, that causes the producer to be called
What I've already looked through:
I've read following articles / SO questions without gaining any better understanding on why the above (1st) solution works as it does.
ViewScoped bean is recreated everytime I click on commandButton in my dataTable
Why does @PostConstruct callback fire every time even though bean is @ViewScoped? JSF
How can I pass selected row to commandLink inside dataTable?
http://balusc.blogspot.de/2010/06/benefits-and-pitfalls-of-viewscoped.html
myBean
. Same issue. (Though I wouldn't put logic into models, since they should be dumb). 2. Yes read it, but that refers toactionListener
, and in my case, the re@Produc
tion is after the APPLICATION_INVOCATION, soaction
finds its way correctly – Matyas