PF DataTable store paging/sorting/filtering in Session

UI Components for JSF
Post Reply
userx
Posts: 1
Joined: 26 Aug 2016, 15:30

26 Aug 2016, 15:48

Hi all,

I have the following question: What is the best/intended way to store paging/sorting/filtering information for DataTable in the HTTP Session?
Basically I want to use DataTable + normal columns in View scope, then navigate away to another view. On return, I want to see the last used filters/paging/sorting.

What I have tried so far:
[1] Tried to find some useful DataTable attributes, which can be bound to a session-scoped bean with appropriate EL. I think this works for Paging. I could not get Sorting/Filtering to work. sortBy for table/columns is meant to designate EL that operates on the table row variable, I think. filterBy for columns seems to follow the same approach. filterValue - not sure what this does.
[2] Thought about extending Features - could not find a way to do it :( Feature registry is static with default access. Moreover, copying the entire DataTable class is no good, because e.g. the Features use DataTable in their signatures.
[3] Thought about some workarounds that require Facelets code. For example, have controller listeners for page/sort/filter events, save page/sort/filter data to Session, then on lazy load or in-memory sort get those values. Can be done, but seems not optimal to me (everyone should remember to use events in view, controller event handlers).

So, is there an easy way to preserve paging/sorting/filtering in Session?
Is it built-in, or do we have to somehow extend the PF classes?

Thanks in advance!
PF 6.0/MyFaces 2.2.10/Spring Boot/Tomcat 8.0.36

jrcampins
Posts: 10
Joined: 05 Apr 2016, 19:03

31 Aug 2016, 01:39

I'm also looking for an answer to the same question. So far without much success. If you save the value of dataTable.getFirst() at the @PreDestroy method of the view's backing bean then you can restore it later using dataTable.setFirst(theSavedValue) at a preRenderView listener method. I tried to do something similar with getFilters/setFilters and getMultiSortMeta/setMultiSortMeta but that doesn't work. Let's keep looking.

jrcampins
Posts: 10
Joined: 05 Apr 2016, 19:03

31 Aug 2016, 23:17

I've found a partial but relatively easy solution. I tried to post it but the page throws a General error when I do. I'll try again tomorrow.

kukeltje
Expert Member
Posts: 9605
Joined: 17 Jun 2010, 13:34
Location: Netherlands

01 Sep 2016, 10:28

You might have a non-supported character on your code. A 'euro' sign e.g. is not supported. There might be others. Check for those

jrcampins
Posts: 10
Joined: 05 Apr 2016, 19:03

01 Sep 2016, 17:08

I cannot detect any non-ASCII character in my post. This is the error I get:

General Error
SQL ERROR [ mysqli ]

Incorrect string value: '\xE2\x80\x99s l...' for column 'post_text' at row 1 [1366]

It always fails at row 1 [1366] regardless of the text!

I'll split the text and try posting it in several replies.

jrcampins
Posts: 10
Joined: 05 Apr 2016, 19:03

01 Sep 2016, 17:11

I've found a partial but relatively easy solution. I found it looking at the code of org.primefaces.component.datatable.feature.FilterFeature.

It is a 3-step procedure. I'll try posting each one separately.

jrcampins
Posts: 10
Joined: 05 Apr 2016, 19:03

01 Sep 2016, 17:15

I couldn't even post the first one! It is less than 20 lines long. I don't see any strange character. I send an e-mail to the board administrator last week (similar problem, also at row1 [1366] entirely different text) but I have not received any answer yet.

jrcampins
Posts: 10
Joined: 05 Apr 2016, 19:03

01 Sep 2016, 22:47

I've finally found the illegal character, so here is my answer:

This is a partial but relatively easy solution. I found it looking at the code of org.primefaces.component.datatable.feature.FilterFeature. It is a 3-step procedure.

Step-1. Save the table data you want to restore later. Ideally all data should be saved at PreDestroy, but some has to be saved earlier, at preRenderView because the getter fails at PreDestroy (e.g. multiSortMeta). So you might need to add two methods to the view backing bean. They would look somehow like this:

Code: Select all

    public void saveAtPreRenderView(DataTable dataTable) {
        if (dataTable != null) {
            // getMultiSortMeta at PreDestroy fails
            // ERROR WELD-000019 will appear in server's log
            save(dataTable.getMultiSortMeta());
        }
    }

    public void saveAtPreDestroy(DataTable dataTable) {
        if (dataTable != null) {
            save(dataTable.getFirst());
            save(dataTable.getRows());
            save(dataTable.getFilters());
        }
    }
Step-2. Add the filters as request parameters to the URL/outcome of the link, button, etc. you want to use to go back the page containing the table. You would need something like this:

Code: Select all

    String rpl = "";
    Map<String, Object> filters = dataTableState.getFilters();
    if (filters != null && !filters.isEmpty()) {
        Set<String> keySet = filters.keySet();
        for (String key : keySet) {
            Object obj = filters.get(key);
            if (obj != null) {
                String cid = DATA_TABLE_ID
                    + ":" + key + "Column"
                    + ":" + "filter";

                rpl += "&" + cid + "=" + obj;
            }
        }
    }
As you might have already guessed, DATA_TABLE_ID is the DataTable component id (something like myForm:myDataTable); the id of the columns would be the filtered field name (which is used as key of the filters map) plus a suffix (like "Column"); for instance, the column for customerName would look like this:

Code: Select all

                <p:column
                    id="customerNameColumn"
                    sortBy="#{currentRow.customerName}"
                    filterBy="#{currentRow.customerName}"
                    filterMatchMode="contains"
                    headerText="Customer Name">
                    #{currentRow.customerName}
                </p:column>
Step-3. Restore the data you saved earlier. It should be restored at preRenderView. Finally, filter and sort the data (this is the tricky part). You would need a method like this:

Code: Select all

    public void restore(DataTable dataTable) {
        if (dataTable != null) {
            dataTable.setFirst(firstSavedValue);
            dataTable.setRows(rowsSavedValue);
            dataTable.setFilters(filtersSavedValue);
            dataTable.setMultiSortMeta(multiSortMetaSavedValue);
            FacesContext facesContext = FacesContext.getCurrentInstance();
            //  Filter like FilterFeature.encode
            FilterFeature filterFeature = (FilterFeature) dataTable.getFeature(DataTableFeatureKey.FILTER);
            List<FilterMeta> filterMetaData = filterFeature.populateFilterMetaData(facesContext, dataTable);
            String globalFilterParam = dataTable.getClientId(facesContext) + ":" + "globalFilter";
            filterFeature.filter(facesContext, dataTable, filterMetaData, globalFilterParam);
            //  Sort like FilterFeature.encode and DataTableRenderer.preRender
            SortFeature sortFeature = (SortFeature) dataTable.getFeature(DataTableFeatureKey.SORT);
            if (dataTable.isMultiSort()) {
                if (dataTable.getMultiSortMeta() != null) { // check multiSortMeta because multiSort fails when it is null
                    sortFeature.multiSort(facesContext, dataTable);
                }
            } else {
                sortFeature.singleSort(facesContext, dataTable);
            }        
        }
    }
There is a lot of details that still need your attention but I hope this would get you started.

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 34 guests