Question

I have set up an AsyncDataProvider for my CellTable and added it to a SimplePager. I have hooked up a ListHandler to take care of sorting based on a column. When I click the header of that column, the data doesn't change but on going to the next/previous page within the pager the data is then sorted. Also before the column is clicked there is no visual indicator on the column that would indicate that it is meant to be sortable.

How can I get the data to update when I click the header of the Column?

Here's my code snippet

service.getHosts(environment, new AsyncCallback<Set<String>>() {    
        @Override
        public void onSuccess(final Set<String> hosts) {
            final List<String> hostList = new ArrayList<String>(hosts);
            //Populate the table
            CellTable<String> hostTable = new CellTable<String>();
            TextColumn<String> hostNameColumn = new TextColumn<String>(){
                @Override
                public String getValue(String string){
                    return string;
                }
            };

            NumberCell numberCell = new NumberCell();
            Column<String, Number> lengthColumn = new Column<String, Number>(numberCell){

                @Override
                public Number getValue(String string) {
                    return new Integer(string.length());
                }

            };

            AsyncDataProvider<String> dataProvider = new AsyncDataProvider<String>() {
                @Override
                protected void onRangeChanged(HasData<String> data) {
                    int start = data.getVisibleRange().getStart();
                    int end = start + data.getVisibleRange().getLength();
                    List<String> subList = hostList.subList(start, end);
                    updateRowData(start, subList);
                }

            };
            // Hooking up sorting
            ListHandler<String> columnSortHandler = new ListHandler<String>(hostList);
            columnSortHandler.setComparator(lengthColumn, new Comparator<String>(){

                @Override
                public int compare(String arg0, String arg1) {
                    return new Integer(arg0.length()).compareTo(arg1.length());
                }

            });
            hostTable.setPageSize(10);
            hostTable.addColumnSortHandler(columnSortHandler);
            hostTable.addColumn(hostNameColumn,"Host Name");
            lengthColumn.setSortable(true);
            hostTable.addColumn(lengthColumn, "Length");

            VerticalPanel verticalPanel = new VerticalPanel();
            SimplePager pager = new SimplePager();
            pager.setDisplay(hostTable);
            dataProvider.addDataDisplay(hostTable);
            dataProvider.updateRowCount(hosts.size(), true);
            verticalPanel.add(hostTable);
            verticalPanel.add(pager);
            RootPanel.get().add(verticalPanel);
        }

        @Override
        public void onFailure(Throwable throwable) {
            Window.alert(throwable.getMessage());

        }
    });

I'm not sure how to make sure that the list is shared by both the table and the Pager. Before adding the pager I was using

    ListDataProvider<String> dataProvider = new ListDataProvider<String>();

    ListHandler<String> columnSortHandler = new ListHandler<String>(dataProvider.getList());

The AsyncDataProvider doesn't have the method getList.

To summarize I want the data to be sorted as soon as the column is clicked and not after I move forward/backward with the pager controls.

As per the suggestion I have changed the code for the AsyncDataProvider to

AsyncDataProvider<String> dataProvider = new AsyncDataProvider<String>() {
                    @Override
                    protected void onRangeChanged(HasData<String> data) {
                        int start = data.getVisibleRange().getStart();
                        int end = start + data.getVisibleRange().getLength();
                        List<String> subList = hostList.subList(start, end);

                                // Hooking up sorting
                                ListHandler<String> columnSortHandler = new ListHandler<String>(hostList);
                                hostTable.addColumnSortHandler(columnSortHandler);
                                columnSortHandler.setComparator(lengthColumn, new Comparator<String>(){

                                    @Override
                                    public int compare(String v0, String v1) {
                                        return new Integer(v0.length).compareTo(v1.length);
                                    }

                                });
                        updateRowData(start, subList);
                    }

                }; 

But there is no change in the behavior even after that. Can someone please explain the process. The GWT showcase app seems to have this functionality but how they've done it isn't all that clear.

Was it helpful?

Solution

When using an AsyncDataProvider both pagination and sorting are meant to be done on the server side. You will need an AsyncHandler to go with your AsyncDataProvider:

    AsyncHandler columnSortHandler = new AsyncHandler(dataGrid) {

        @Override
        public void onColumnSort(ColumnSortEvent event) {

            @SuppressWarnings("unchecked")
            int sortIndex = dataGrid.getColumnIndex((Column<Entry, ?>) event.getColumn());
            boolean isAscending = event.isSortAscending();

            service.getPage(0, sortIndex, isAscending, new AsyncCallback<List<Entry>>() {

                public void onFailure(Throwable caught) {
                }


                public void onSuccess(List<Entry> result) {

                    pager.setPage(0);
                    provider.updateRowData(0, result);
                }
            });
        }
    };
    dataGrid.addColumnSortHandler(columnSortHandler);

Clicking on a column header will then fire a columnSortEvent. Then you have to get the column clicked. I am overloading my servlet to provide both sorting and pagination, so I pass a -1 for the column index when only pagination is desired.

    provider = new AsyncDataProvider<Entry>() {

        @Override
        protected void onRangeChanged(HasData<Entry> display) {

            final int start = display.getVisibleRange().getStart();

            service.getPage(start, -1, true, new AsyncCallback<List<Entry>>() {

                @Override
                public void onFailure(Throwable caught) {
                }


                @Override
                public void onSuccess(List<Entry> result) {

                    provider.updateRowData(start, result);
                }
            });
        }
    };

    provider.addDataDisplay(dataGrid);
    provider.updateRowCount(0, true);

Then your servlet implementation of getPage performs the sorting and pagination. The whole thing is much easier to follow with separate event handlers.

OTHER TIPS

I think the problem is with the ListHandler initialization. You are passing hostList as a parameter to List Handler and in onRangeChange method you are calling updateRowData with a different list (sublist).

Make sure you use the same list in both the places.

or

Move your ListHander initialization and cellTable.addColumnSortHandler method call to onRangeChange method after updateRowData call.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top