2013-08-31 85 views
12

Vấn đề của tôi là sau khi tôi đã chọn một vài mục trên trang đầu tiên, nếu tôi phân trang đến một trang khác và quay trở lại, lựa chọn ban đầu của tôi không được hiển thị. Tôi đã cố gắng để thực hiện các SelectableDataModel cũng như sử dụng các rowKey thuộc tính nhưng vấn đề vẫn tồn tại.p: các lựa chọn dataTable bị mất sau khi phân trang một LazyDataModel

Đây là đậu thử nghiệm của tôi:

@ManagedBean 
@ViewScoped 
public class MrBean { 
    private List<Item> chosenItems; 
    private LazyDataModel lazyModel; 

    @PostConstruct 
    public void prepareTest() { 
     this.lazyModel = new LazyItemDataModel(); 
    } 

    public void countItems() { 
     System.out.println("TEST 3: chosenItems's size: " + chosenItems.size()); 
    } 

    private class LazyItemDataModel extends LazyDataModel<Item> implements SelectableDataModel<Item> { 
     @Override 
     public Item getRowData(String rowKey) { 
      System.out.println("TEST 1: getRowData"); 
      Iterator<Item> iter = ((List<Item>) this.getWrappedData()).iterator(); 
      while (iter.hasNext()) { 
       Item item = iter.next(); 
       if (item.getId().equals(rowKey)) { 
        return item; 
       } 
      } 

      return null; 
     } 

     @Override 
     public Object getRowKey(Item item) { 
      return item.getId(); 
     } 

     @Override 
     public List<Item> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map filters) { 
      System.out.println("TEST 2: load"); 
      // Code to retrieve items from database 
     } 
    } 

    // Getters and Setters 
} 

Đây là trang thử nghiệm của tôi:

<?xml version='1.0' encoding='UTF-8' ?> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" 
     xmlns:h="http://java.sun.com/jsf/html" 
     xmlns:p="http://primefaces.org/ui"> 
    <h:head> 
     <title>Test page</title> 
    </h:head> 
    <h:body> 
     <h:form> 
      <p:dataTable id="itemTable" var="item" value="#{mrBean.items}" rows="5" 
         paginator="true" selection="#{mrBean.chosenItems}" lazy="true" > 

       <p:ajax event="rowSelectCheckbox" listener="mrBean.countItems" />      

       <p:column selectionMode="multiple" /> 

       <p:column headerText="ID"> 
        <h:outputText value="#{item.id}" /> 
       </p:column> 

       <p:column headerText="Name"> 
        <h:outputText value="#{item.name}" /> 
       </p:column> 

      </p:dataTable> 
     </h:form> 
    </h:body> 
</html> 

Tôi sẽ rất biết ơn nếu bạn có thể chỉ cho tôi những gì tôi đã làm sai ở đây.

UPDATE: Sau khi tôi thêm nhiều System.out.println("TEST") vào mã ở trên, tôi đã quan sát những điều sau đây:

  1. Trên giao diện điều khiển, mỗi khi tôi đánh số trang, TEST 1: getRowData luôn in trước TEST 2: load. Kết quả là tôi tin phương thức #LazyDataModel.getWrappedData() có thể trả về dữ liệu từ trang cũ. Lúc đầu, tôi nghĩ mục tiêu của phương pháp này là lấy các hàng đã chọn để tô sáng trên bàn. Tuy nhiên, nếu phương pháp này được gọi trước load, không có cách nào nó có thể thực hiện công việc đúng không?
  2. Sau khi tôi chọn 2 mục đầu tiên trên trang đầu tiên, trên bảng điều khiển, tôi đã thấy TEST 3: chosenItems's size: 2. Nếu tôi phân trang đến trang thứ 2 và sau đó quay lại trang thứ nhất, các lựa chọn sẽ bị mất như đã đề cập. Tuy nhiên, nếu tôi tiếp tục chọn một mục khác, trên bảng điều khiển, tôi thấy TEST 3: chosenItems's size: 3. Rõ ràng, danh sách chosenItems vẫn giữ các lựa chọn cũ của tôi nhưng chúng không được hiển thị trên bảng.
+0

+1 để cung cấp một SSCCE đơn giản và có thể kiểm tra ;-) Thời gian tới xem xét việc thêm một phân lớp 'Item' để làm cho nó copy'paste'run –

+0

Tôi không chắc chắn về vấn đề cụ thể. Đậu của bạn được xem scoped, chắc chắn nó sẽ được tái tạo với tất cả các thuộc tính của nó thiết lập để mặc định khi bạn truy cập lại trang? Nếu bạn muốn tương tác với cùng một chế độ xem, thì bạn nên xem xét hiển thị kết quả có điều kiện trong cùng một chế độ xem thay vì chuyển sang chế độ xem khác. – BalusC

+0

@BalusC Tôi nghĩ rằng khi anh ấy nói về việc chuyển sang trang khác, anh ấy thực sự có nghĩa là các trang bảng (paginator) thay vì các khung nhìn. –

Trả lời

0

Tôi gặp vấn đề tương tự với bảng dữ liệu của mình. Mặc dù trường hợp của tôi hơi khác một chút vì tôi đang sử dụng selectBooleanCheckbox thay thế. Tôi tìm thấy một giải pháp đơn giản phù hợp với tôi. Nó đánh tôi khi bạn nói "lựa chọn cũ không được trả lại trong bảng".

  • dây đeo hộp kiểm với một a4j : sự kiện hỗ trợ

mã:

<h:selectBooleanCheckbox value="#{batch.toPortfolio}"> 
    <a4j:support event="onchange" /> 
</h:selectBooleanCheckbox> 
1

Điều này là do khi SelectionFeature được giải mã một danh sách mới được tạo ra.

Và nếu table.getRowData(rowKeys[i]) (liên quan đến thực hiện LazyDataModel của bạn) trả về null Selections cũ của bạn ở trang trước là gone.may cố gắng giải quyết nó bằng cách thay đổi thực hiện LazyDataModel của bạn tôi đã không cố gắng này, nhưng hãy nhìn vào thisthis

Có cùng vấn đề và tôi nghĩ giải pháp này dễ dàng hơn nếu bạn có nhiều bảng khác nhau triển khai LazyDataModel.

Đây là những gì tôi đã làm: kiểm tra nếu nó là lười đầu tiên sau đó thêm hàng hiện đang được chọn vào danh sách lựa chọn.

Đối với các nguyên tố 4.0

1) Override DataTableRenderer

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

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 decode SelectionFeature của

Cập nhật: chỉnh sửa để cho phép bỏ chọn

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); 
      } 
     } 
    } 
} 

Có thể không phải là giải pháp tốt nhất nhưng nên làm việc, cho tôi biết nếu có một cách tốt hơn. Hy vọng điều này sẽ giúp một ai đó.

+0

Giải pháp của Ceyda hoạt động - nó bảo tồn để lựa chọn sau khi phân trang. Nhưng có một vấn đề, sau khi lựa chọn bạn sẽ không thể bỏ chọn nó - tại sao? – Gilberto

+0

Tôi nghĩ rằng nó là cần thiết một sự điều chỉnh trong tập tin datatable.js là tốt. – Gilberto

+0

@Gilbertoca Tôi nghĩ rằng thay đổi 'if (rowData! = Null &&! SelectionList.contains (rowData)) selectionList.add (rowData);' ở cuối _for_ trong _if (lazy) _ phần thành 'if (rowData! = null) { \t if (! selectionList.contains (rowData)) {selectionList.add (rowData);} \t else {selectionList.remove (rowData);} } 'sẽ hoạt động nếu tôi nhớ chính xác.Đã lâu rồi tôi không còn có mã hoặc môi trường thử nghiệm để cho tôi biết nếu nó hoạt động và tôi sẽ cập nhật câu trả lời. – Ceyda

1

Chỉ cần thực hiện bất động sản chắc chắn sẽ sở hữu lựa chọn các DataTable (selection="#{pageBackingForm.selectedEntityList}") như thế này và nó sẽ làm việc:

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(); 
    } 
1

trong trang web chỉ cần thêm một sự kiện cho khi chuyển đổi trang:

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

Trong listingBean, chỉ cần lưu lựa chọn:

private List<GInstance> selectedInstances; 
private List<GInstance> selectedInstancesSaved; 

public List<GdWFInstance> getSelectedInstances() 
{ 
    return selectedInstancesSaved; 
} 

public void setSelectedInstances(List<GdWFInstance> selectedInstances) 
{ 
    this.selectedInstances = selectedInstances; 
} 

public void updateSelected() 
{ 
    if (selectedInstances != null && !selectedInstances.isEmpty()) { 
     for (GInstance inst : lazyModel.getDatasource()) { 
      if (selectedInstances.contains(inst)) { 
       selectedInstancesSaved.add(inst); 
      } else { 
       selectedInstancesSaved.remove(inst); 
      } 
     } 
    } 
} 
+0

Cảm ơn, điều này đã làm việc hoàn hảo, đơn giản và dễ hiểu :) –