jsf-2primefacesdatatableflash-scopeprerenderview

Data from <p:dataTable> which is obtained from flash scope during preRenderView event is lost when pagination or sorting is performed


I have a paginable and sortable <p:dataTable>:

<p:dataTable var="item" value="#{reporteIngresosPorExtranetController.detalle}"
    paginator="true" rows="10" paginatorPosition="bottom" rowsPerPageTemplate="5,10,15"
    paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}">
    <p:column sortBy="#{item.user}" headerText="USUARIO:">
        <h:outputText value="#{item.user}" />
    </p:column>
    ...
</p:dataTable>

Its data is obtained from the flash scope into a @ViewScoped bean during the preRenderView event:

<f:event type="preRenderView" listener="#{reporteIngresosPorExtranetController.cargarDatos}" />
public void cargarDatos() {
    detalle = (List<Map<String, Object>>) FacesUtils.flashScope().get("RIE_detalle");
}

When I perform pagination or sorting, then the data is lost. How is this caused and how can I solve it?


Solution

  • You seem to think that the preRenderView is executed only once during creation of the view scope. This is Wrong. The preRenderView is executed during every HTTP request right before rendering the view (read the event name once again, it should now make more sense, right?). Pagination and sorting is performed by ajax. Every ajax request is also considered a HTTP request. Flash scoped data has a lifetime of exactly one redirect. Flash scoped data isn't available anymore on all subsequent requests unless explicitly set in the flasch scope once again. So basically, your listener method is re-invoked on every pagination and sorting request which effectively sets detalle to null.

    Get rid of the <f:event> altogether and put a @PostConstruct annotation on the method. This way it's really invoked only once during creation of the view scope, exactly as you intented.

    @PostConstruct
    public void cargarDatos() {
        detalle = (List<Map<String, Object>>) FacesUtils.flashScope().get("RIE_detalle");
    }
    

    See also:


    Unrelated to the concrete problem, this design is ... kind of strange. I'd really consult a more experienced JSF architect about how to properly achieve the concrete functional requirement for which you possibly incorrectly thought that using the flash scope this way would be the right approach.