sortMode="multiple" and lazy="true" in <p:dataTable> clears multisort meta during pagination

10,120

I solved this question in a temporary way... Have a sessionscoped managed bean for storing the sorting column details, inorder to get within load() during pagination, like:-

@ManagedBean
@SessionScoped

public class StoreSortColumnDetail implements Serializable{


    /** holds multisort values**/
private List<SortMeta> mMultiSortMeta;


public List<SortMeta> getMultiSortMeta() {
    return mMultiSortMeta;
}

public void setMultiSortMeta(List<SortMeta> multiSortMeta) {
    mMultiSortMeta = multiSortMeta;
}

public void clearMultiSortMeta() {
    if(this.mMultiSortMeta != null)
        this.mMultiSortMeta.clear();

}
}

and use it in load() as like this:

@Override
public List<Car> load(int first, int pageSize, 
                  List<SortMeta> multiSortMeta,Map<String, String> filters) {

/** Instance to the SessionScoped scoped StoreSortColumnDetail managed bean*/
@ManagedProperty(value="#{StoreSortColumnDetail }")
private StoreSortColumnDetail storeSortColumnDetail ;

public void setStoreSortColumnDetail (StoreSortColumnDetail sortColumnDetail ) {
    this.storeSortColumnDetail = sortColumnDetail ;
}

/** to hold the handled sort column detail**/
List<SortMeta> handledMultiSortMeta = new ArrayList<SortMeta>();

/*Here starts the multisortmeta handling process*/
   /** check for List<SortMeta> for null**/
if(multiSortMeta != null ) {

    /** updates StoreSortColumnDetail's List<SortMeta> with Load()'s List<SortMeta>**/
    storeSortColumnDetail.setMultiSortMeta(multiSortMeta);
    handledMultiSortMeta  = multiSortMeta;
} 
/** check for List<SortMeta> for notnull **/
else if (multiSortMeta == null) {

    /**assigns Load()'s List<SortMeta> with StoreSortColumnDetail's List<SortMeta>**/
    handledMultiSortMeta  = storeSortColumnDetail.getMultiSortMeta();
} 


   /*Now u have handled multisortmeta from load()...
     and u can process now from handledMultiSortMeta*/
}

i hope u came to know how i handled, if not intimate me... but this is a temporary way,need to handle it through primefaces way...

Share:
10,120
senthil_sss
Author by

senthil_sss

Updated on June 07, 2022

Comments

  • senthil_sss
    senthil_sss almost 2 years

    I just enabled multiple sorting in the showcase code for "DataTable - Lazy Loading"

    datatableLazy.xhtml

    <html lang="en" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui"
    xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:head>
    <title>CarDataTable</title>
    </h:head>
    <h:body>
    <h:form id="form">
        <p:dataTable var="car" value="#{tableBean.lazyModel}" paginator="true"
            rows="10"
            paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
            rowsPerPageTemplate="5,10,15" id="carTable" lazy="true"
            sortMode="multiple">
    
            <p:ajax event="rowSelect" listener="#{tableBean.onRowSelect}"
                update=":form:display" oncomplete="carDialog.show()" />
    
            <p:column headerText="Model" sortBy="#{car.model}"
                filterBy="#{car.model}">
                <h:outputText value="#{car.model}" />
            </p:column>
    
            <p:column headerText="Year" sortBy="#{car.year}"
                filterBy="#{car.year}">
                <h:outputText value="#{car.year}" />
            </p:column>
    
            <p:column headerText="Manufacturer" sortBy="#{car.manufacturer}"
                filterBy="#{car.manufacturer}">
                <h:outputText value="#{car.manufacturer}" />
            </p:column>
    
            <p:column headerText="Color" sortBy="#{car.color}"
                filterBy="#{car.color}">
                <h:outputText value="#{car.color}" />
            </p:column>
        </p:dataTable>
    </h:form>
    </h:body>
    </html>
    

    TableBean.java

    package com.solartis.primefaces.sample;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.UUID;
    
    import javax.faces.bean.ManagedBean;
    
    import org.primefaces.model.LazyDataModel;
    
    @ManagedBean
    public class TableBean {
    
    private LazyDataModel<Car> lazyModel;
    
    private Car selectedCar;
    
    private List<Car> cars = new ArrayList<Car>();
    
    private final static String[] colors;
    
    private final static String[] manufacturers;
    
    static {
        colors = new String[10];
        colors[0] = "Black";
        colors[1] = "White";
        colors[2] = "Green";
        colors[3] = "Red";
        colors[4] = "Blue";
        colors[5] = "Orange";
        colors[6] = "Silver";
        colors[7] = "Yellow";
        colors[8] = "Brown";
        colors[9] = "Maroon";
    
        manufacturers = new String[10];
        manufacturers[0] = "Mercedes";
        manufacturers[1] = "BMW";
        manufacturers[2] = "Volvo";
        manufacturers[3] = "Audi";
        manufacturers[4] = "Renault";
        manufacturers[5] = "Opel";
        manufacturers[6] = "Volkswagen";
        manufacturers[7] = "Chrysler";
        manufacturers[8] = "Ferrari";
        manufacturers[9] = "Ford";
    }
    
    public TableBean() {
        populateRandomCars(cars, 50);
        lazyModel = new LazyCarDataModel(cars);
    }
    
    public Car getSelectedCar() {
        return selectedCar;
    }
    
    public void setSelectedCar(Car selectedCar) {
        this.selectedCar = selectedCar;
    }
    
    public LazyDataModel<Car> getLazyModel() {
        return lazyModel;
    }
    
    private void populateRandomCars(List<Car> list, int size) {
        for (int i = 0; i < size; i++) {
            list.add(new Car(getRandomModel(), getRandomYear(),
                    getRandomManufacturer(), getRandomColor()));
        }
    }
    
    private String getRandomColor() {
        return colors[(int) (Math.random() * 10)];
    }
    
    private String getRandomManufacturer() {
        return manufacturers[(int) (Math.random() * 10)];
    }
    
    private int getRandomYear() {
        return (int) (Math.random() * 50 + 1960);
    }
    
    private String getRandomModel() {
        return UUID.randomUUID().toString().substring(0, 8);
    }
    }
    

    LazyCarDataModel.java

    package com.solartis.primefaces.sample;
    
    import java.util.ArrayList;
    
    /**
     * Dummy implementation of LazyDataModel that uses a list to mimic a real 
       datasource like a database.
     */
    public class LazyCarDataModel extends LazyDataModel<Car> {
    
    private List<Car> datasource;
    
    public LazyCarDataModel(List<Car> datasource) {
        this.datasource = datasource;
    }
    
    @Override
    public Car getRowData(String rowKey) {
        for(Car car : datasource) {
            if(car.getModel().equals(rowKey))
                return car;
        }
    
        return null;
    }
    
    @Override
    public void setRowIndex(int rowIndex) {
    
        if (rowIndex == -1 || getPageSize() == 0) {
            super.setRowIndex(-1);
        } else
            super.setRowIndex(rowIndex % getPageSize());
    }
    
    @Override
    public Object getRowKey(Car car) {
        return car.getModel();
    }
    
    @Override
    public List<Car> load(int first, int pageSize, 
                          List<SortMeta> multiSortMeta,Map<String, String> filters) {
    
        System.out.println("\nTHE INPUT PARAMETER VALUE OF LOAD METHOD :   
        \t"+"first=" + first + ", pagesize=" + pageSize + ", multiSortMeta=" + 
        multiSortMeta + " filter:" + filters);
    
        System.out.println("\nTHE MULTISORTMETA CONTENT  : \t");
    
        if (multiSortMeta != null) {
            for (SortMeta sortMeta : multiSortMeta) {
                System.out.println("SORTFIELD:" +sortMeta.getSortField());
                System.out.println("SORTORDER:" +sortMeta.getSortOrder());
                        System.out.println("SORTFUNCTION:"
                                                             +sortMeta.getSortFunction());
                System.out.println("COLUMN:" +sortMeta.getColumn());
                System.out.println("CLASS:" +sortMeta.getClass());
            }
        }
    
        List<Car> data = new ArrayList<Car>();
    
        //filter
        for(Car car : datasource) {
            boolean match = true;
    
            for(Iterator<String> it = filters.keySet().iterator(); it.hasNext();) {
                try {
                    String filterProperty = it.next();
                    String filterValue = filters.get(filterProperty);
                    String fieldValue =  String.valueOf(car.getClass().
                                    getField(filterProperty).get(car));
    
                    if(filterValue == null || fieldValue.startsWith(filterValue)) {
                        match = true;
                    }
                    else {
                        match = false;
                        break;
                    }
                } catch(Exception e) {
                    match = false;
                } 
            }
    
            if(match) {
                data.add(car);
            }
        }
    
    
        //rowCount
        int dataSize = data.size();
        this.setRowCount(dataSize);
    
        //paginate
        if(dataSize > pageSize) {
            try {
                return data.subList(first, first + pageSize);
            }
            catch(IndexOutOfBoundsException e) {
                return data.subList(first, first + (dataSize % pageSize));
            }
        }
        else {
            return data;
        }
    }
    }
    

    It works well except when I paginate with multiple columns sorting, the load() method with List<SortMeta> does not give me the column details which are currently sorted to carry over to the other page, unlike the load() method with String sortField, SortOrder sortOrder which gives those sorting details.

    For example:

    1. Click on the sorting arrow in "manufacturer" and then Ctrl+click on the sorting arrow of "year"

      • you would get the sorting column details to the load() method (I have printed the input parameters value inside load method).
    2. Now, do pagination. Here the load() method fails to give the sorting columns detail

      • not only for pagination, if you enter column filter values after clicking on the sorting columns, the same problem exist

    How can I fix this?

  • senthil_sss
    senthil_sss almost 11 years
    @Tiny: plz..take a look at my answer and give ur comments
  • Tiny
    Tiny almost 11 years
    Yeah! Thank you for answering this question. I will see this later in a few days, since I'm currently a bit busy with other stuff for a few days. Please keep it up. Don't delete it.
  • Tiny
    Tiny almost 11 years
    Yes, I gave it a try and it worked great. Nevertheless it is still incomplete to meet my requirements because sortColumn should be retained (with column highlight and sort derection) on the client-side even after dataTable is rendered i.e when <p:commandButton> is pressed to add a row into the database and consequently into dataTable which doesn't happen util some JavaScript magic is used. I tried the answers to this question but unfortunately none of them worked for me as expected. Did you do that in your application? Thanks so much.
  • senthil_sss
    senthil_sss almost 11 years
    @Tiny: unfortunately i didn't take up ur scenario.I will try urs and inform u soon
  • senthil_sss
    senthil_sss almost 11 years
    @Tiny: can u get me something to this unrelated issue : stackoverflow.com/questions/17145023/…
  • Tiny
    Tiny almost 11 years
    I've looked into your previous question. Until now, I didn't use <cc:interface> and <cc:implementation> though I gave it a try after reading some tutorials but it didn't work for me. It requires me to spend sometime on it. Therefore, I'm right now unable to see the cause of that exception, sorry. Nevertheless, I'll keep trying though, hoping you'll get answer(s) before that. (I'm currently more comfortable in Spring than JSF).
  • senthil_sss
    senthil_sss almost 11 years
    @Tiny : ok..no probs..i'll reply u soon,regarding ur scenario!!.
  • Tiny
    Tiny almost 11 years
    Back to my previous comment : if it doesn't work reasonably, then I want to start a bounty on your question to see, if someone has a reliable solution or not. If not, then I want to leave Primefaces forever because in addition to this issue in the question, I found so many other issues in this framework (with the status "WontFix" in the next release or so) and many of them are likely to be encountered on its way. My application is pending for months because of these issues. Thank you very much for your help, sir.
  • Kukeltje
    Kukeltje over 8 years
    If you override core PF classes, it is good to also state which version this was for! (it is good to mention version info at all times as a matter of fact)
  • YamYamm
    YamYamm over 8 years
    you are correct, i believe this solution is good for any primefaces version above 5.0, also overriding is not mandatory here, i meant directly using concrete BeanPropertyComparator class by instantiating a new object.