19

私の問題は、最初のページでいくつかのアイテムを選択した後、別のページに移動して戻ってきた場合、最初の選択が表示されないことです。SelectableDataModelを実装して属性を使用しようとしましrowKeyたが、問題は解決しません。

これは私のテスト Bean です。

@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
}

これは私のテストページです:

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

ここで私が間違ったことを教えていただければ、とても感謝しています。

更新:上記のコードにさらに追加System.out.println("TEST")した後、次のことを確認しました。

  1. コンソールでは、ページネーションを行うたびに、TEST 1: getRowData常に前に出力されTEST 2: loadます。結果として、メソッド#LazyDataModel.getWrappedData()は古いページからデータを返す可能性があると思います。最初は、このメソッドの目的は、選択された行を取得してテーブルで強調表示することだと思っていました。しかし、このメソッドがloadの前に呼び出された場合、正しく機能する方法はありませんか?
  2. 最初のページで最初の 2 つの項目を選択すると、コンソールに が表示されましたTEST 3: chosenItems's size: 2。2 ページ目に移動してから 1 ページ目に戻ると、前述のように選択が失われます。ただし、コンソールで別の項目を選択し続けると、 が表示されましたTEST 3: chosenItems's size: 3。明らかに、chosenItemsリストには古い選択が保持されていますが、テーブルには表示されません。
4

5 に答える 5

2

これは、SelectionFeatureがデコードされると新しいリストが作成されるためです。

そして、table.getRowData(rowKeys[i])(実装に関連してLazyDataModel) null を返す場合、前のページの古い選択はなくなっています。LazyDataModel の実装を変更して解決しようとするかもしれませ

同じ問題がありましたが、LazyDataModel を実装するさまざまなテーブルが多数ある場合、このソリューションはより簡単だと思います。

これは私がやったことです: 最初に遅延しているかどうかを確認してから、現在選択されている行を selectionList に追加します。

プライムフェイス 4.0 の場合

1)DataTableRenderer をオーバーライドする

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)SelectionFeature のデコードをオーバーライドする

更新: 選択解除できるように編集

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

最善の解決策ではないかもしれませんが、うまくいくはずです。より良い方法があれば教えてください。これが誰かに役立つことを願っています。

于 2014-06-23T07:40:05.730 に答える
-1

データテーブルにも同じ問題がありました。代わりにselectBooleanCheckboxを使用しているため、私の場合は少し異なります。自分に合った簡単な解決策を見つけました。「古い選択がテーブルにレンダリングされない」と言ったとき、それは私を襲った。

  • a4j:support イベントでチェックボックスをストラップします

コード:

<h:selectBooleanCheckbox value="#{batch.toPortfolio}">
    <a4j:support event="onchange" />
</h:selectBooleanCheckbox>
于 2013-11-07T04:16:33.120 に答える