p:dataTable selections are lost after paginating a LazyDataModel

后端 未结 5 1243
春和景丽
春和景丽 2021-01-04 00:31

My problem is that after I\'ve selected a few items on the 1st page, if I paginate to another page and come back, my initial selections are not shown. I\'ve tried to impleme

相关标签:
5条回答
  • 2021-01-04 01:06

    While Bruno's solution works for keeping selections across paginations, it doesn't account for retaining selections on an individual page (i.e. when never changing pages).

    This problem can be resolved more simply by using the rowSelectCheckbox and rowUnselectCheckbox ajax events, in addition to having a separate "saved" row list.

    JSF:

     <p:dataTable selection="#{myBean.selectedRows}" ... >
       <p:ajax event="rowSelectCheckbox" process="@this" listener="#{myBean.onSelectRow}" />
       <p:ajax event="rowUnselectCheckbox" process="@this" listener="#{myBean.onUnselectRow}" />
       <p:column selectionMode="multiple" ... />
        ...
     </p:dataTable>
    

    Backing Bean:

        private List<MyRowClass> selectedRows;
        private List<MyRowClass> selectedRowsSaved;
    
        ...
    
        public void onSelectRow(SelectEvent event){
            MyRowClass row = (MyRowClass) event.getObject();
            selectedRowsSaved.add(row);
        }
    
        public void onUnselectRow(UnselectEvent event){
            MyRowClass row = (MyRowClass) event.getObject();
            selectedRowsSaved.remove(row);
        }
    
        public List<MyRowClass> getSelectedRows(){
            return selectedRowsSaved;
        }
    
        public void setSelectedRows(List<MyRowClass> selectedRows){
            this.selectedRows = selectedRows;
        }
    

    This way the list of saved rows is always kept up to date without needing a "page" ajax event.

    0 讨论(0)
  • 2021-01-04 01:06

    In webPage just add a event for when page switch:

    <p:ajax event="page" listener="#{listingBean.updateSelected()}" />
    

    In the listingBean, just save the selected:

    private List<Entity> selectedInstances;
    private List<Entity> selectedInstancesSaved;
    
    public List<Entity> getSelectedInstances()
    {
        return selectedInstancesSaved;
    }
    
    public void setSelectedInstances(List<Entity> selectedInstances)
    {
        this.selectedInstances = selectedInstances;
    }
    
    public void updateSelected()
    {
        if (selectedInstances != null && !selectedInstances.isEmpty()) {
            for (Entity inst : lazyModel.getDatasource()) {
                if (selectedInstances.contains(inst)) {
                    selectedInstancesSaved.add( inst);
                } else {
                    selectedInstancesSaved.remove( inst);
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-04 01:15

    I had the same problem with my data table. Although my case is a bit different because I am using selectBooleanCheckbox instead. I found a simple solution that works for me. It hit me when you said "old selection are not rendered in the table".

    • strap the checkbox with a a4j:support event

    code:

    <h:selectBooleanCheckbox value="#{batch.toPortfolio}">
        <a4j:support event="onchange" />
    </h:selectBooleanCheckbox>
    
    0 讨论(0)
  • 2021-01-04 01:21

    This is because when SelectionFeature is decoded a new list is created.

    And if table.getRowData(rowKeys[i]) (related to your LazyDataModel implementation) returns null your old selectıons in the previous page are gone.may try to solve it by changing your LazyDataModel implementation I didn't try these but take a look at this and this

    Had the same problem and I think this solution is easier if you have a lot of different tables implementing LazyDataModel.

    This is what I did: check if it is lazy first then add currently selected rows to the selectionList.

    For primefaces 4.0

    1)Override DataTableRenderer

    In faces-config.xml

    <render-kit>
       <renderer>
           <component-family>org.primefaces.component</component-family>
           <renderer-type>org.primefaces.component.DataTableRenderer</renderer-type>
           <renderer-class>com.package.LazyDataTableRenderer</renderer-class>
       </renderer>
    </render-kit>
    

    And

    public class LazyDataTableRenderer extends DataTableRenderer {
    static Map<DataTableFeatureKey,DataTableFeature> FEATURES;
    
        static {
            FEATURES = new HashMap<DataTableFeatureKey,DataTableFeature>();
            FEATURES.put(DataTableFeatureKey.DRAGGABLE_COLUMNS, new DraggableColumnsFeature());
            FEATURES.put(DataTableFeatureKey.FILTER, new FilterFeature());
            FEATURES.put(DataTableFeatureKey.PAGE, new PageFeature());
            FEATURES.put(DataTableFeatureKey.SORT, new SortFeature());
            FEATURES.put(DataTableFeatureKey.RESIZABLE_COLUMNS, new ResizableColumnsFeature());
            FEATURES.put(DataTableFeatureKey.SELECT, new LazySelectionFeature());
            FEATURES.put(DataTableFeatureKey.ROW_EDIT, new RowEditFeature());
            FEATURES.put(DataTableFeatureKey.CELL_EDIT, new CellEditFeature());
            FEATURES.put(DataTableFeatureKey.ROW_EXPAND, new RowExpandFeature());
            FEATURES.put(DataTableFeatureKey.SCROLL, new ScrollFeature());
        }
    
        @Override
        public void decode(FacesContext context, UIComponent component) {
            DataTable table = (DataTable) component;
    
            for(Iterator<DataTableFeature> it = FEATURES.values().iterator(); it.hasNext();) {
                DataTableFeature feature = it.next();
    
                if(feature.shouldDecode(context, table)) {
                    feature.decode(context, table);
                }
            }
    
            decodeBehaviors(context, component);        
        }
    }
    

    2)Override SelectionFeature's decode

    Updated: edited to allow deselecting

    public class LazySelectionFeature extends org.primefaces.component.datatable.feature.SelectionFeature{
    
        @Override
        public void decode(FacesContext context, DataTable table) {
            String clientId = table.getClientId(context);
            Map<String,String> params = context.getExternalContext().getRequestParameterMap();
    
            String selection = params.get(clientId + "_selection");
    
            if(table.isSingleSelectionMode())
                decodeSingleSelection(table, selection);
            else
                decodeMultipleSelection(context, table, selection);
        }
    
        void decodeSingleSelection(DataTable table, String selection) {
                if(ComponentUtils.isValueBlank(selection))
                    table.setSelection(null);
                else
                    table.setSelection(table.getRowData(selection));
            }
    
        void decodeMultipleSelection(FacesContext context, DataTable table, String selection) {
            Class<?> clazz = table.getValueExpression("selection").getType(context.getELContext());
            boolean isArray = clazz.isArray();
    
            if(!isArray && !List.class.isAssignableFrom(clazz)) {
                throw new FacesException("Multiple selection reference must be an Array or a List for datatable " + table.getClientId());
            }
    
            if(ComponentUtils.isValueBlank(selection)) {
                if(isArray) {
                    table.setSelection(Array.newInstance(clazz.getComponentType(), 0));
                }
                else {
                    table.setSelection(new ArrayList<Object>());
                }
            }
            else {
                String[] rowKeys = selection.split(",");
                List<Object> selectionList = new ArrayList<Object>();
    
                boolean lazy=table.isLazy();
                if (lazy) {
    
                List<String> currentRowKeys = new ArrayList<String>(Arrays.asList(rowKeys));
                if (table.getSelection() != null) {
                    List<Object> alreadySelected = (List<Object>) table.getSelection();
    
                    for (Object object : alreadySelected) {//For deselecting
                        Object rowKeyFromModel = table.getRowKeyFromModel(object);
                        if (currentRowKeys.contains(rowKeyFromModel)) {
                            selectionList.add(object);
                            currentRowKeys.remove(rowKeyFromModel);
                        } 
                    }                    
                }
                for (String key : currentRowKeys) {//For selecting  
                    Object rowData = table.getRowData(key);
                    if (rowData != null && !selectionList.contains(rowData)) {
                           selectionList.add(rowData);
                    }
                }
    
            }else{
    
                    for(int i = 0; i < rowKeys.length; i++) {
                        Object rowData = table.getRowData(rowKeys[i]);
    
                        if(rowData != null)
                            selectionList.add(rowData);
                    }
    
                }
    
                if(isArray) {
                    Object selectionArray = Array.newInstance(clazz.getComponentType(), selectionList.size());
                    table.setSelection(selectionList.toArray((Object[]) selectionArray));
                }
                else {
                    table.setSelection(selectionList);
                }
            }
        }
    }
    

    Might not be the best solution but should work, let me know if there is a better way. Hope this helps someone.

    0 讨论(0)
  • 2021-01-04 01:26

    Just implement the property bound to selection property of DataTable (selection="#{pageBackingForm.selectedEntityList}") like this and it will work :

        private Map<Integer, List<Entity>> selectedEntityListMap = new Hashtable<>();
    
        public List<Entity> getSelectedEntityList() {
            return selectedEntityListMap.get(getCurrentEntitySelectionPage());
        }
    
        public void setSelectedEntityList(List<Entity> selectedEntityList) {
            if (selectedEntityList == null) {
                selectedEntityListMap.remove(getCurrentEntitySelectionPage());
                return;
            }
    
            selectedEntityListMap.put(getCurrentEntitySelectionPage(), selectedEntityList);
        }
    
        public Integer getCurrentEntitySelectionPage() {
            DataTable dataTable = (DataTable) FacesContext.getCurrentInstance().getViewRoot().findComponent("formId:dataTableId");
            return dataTable.getPage();
        }
    
    0 讨论(0)
提交回复
热议问题