Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 537
senthil_sss Avatar asked Mar 18 '13 04:03

senthil_sss


1 Answers

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...

like image 73
senthil_sss Avatar answered Dec 07 '22 23:12

senthil_sss