0
votes

I have found an interesting issue, and I am wondering if I am misusing or overlooking something. I have a large CellTable that is vertically scrollable. I want to show all the rows at once instead of traditional pagination. So at the bottom of my table I have a row that the user can click to load 50 more rows. I have provided the table with a custom table builder (setTableBuilder(new Builder());). When the user clicks "load more" I query the data, add to the ListDataProvider and call table.setVisibleRange(0, dataProvider.getList().size());.

I put a log statement in the

@Override
public void buildRowImpl(Object rowValue, int absRowIndex) {
}

method to see when it was building rows. I notice that it would build 0-dataProvider.getList().size() (all the rows), then it would build oldLength-dataProvider.getList().size() (the new rows). For instance, if I have 100 rows and then load 50 more it would build 0-150, and then rebuild 100-50. What I want is for it to only build the new rows, obviously.

So I start debugging to see why it is rebuilding the whole table each time. What I found was in com.google.gwt.user.cellview.client.HasDataPresenter it would set the "redrawRequired" flag to true at line 1325:

else if (range1 == null && range0 != null && range0.getStart() == pageStart
    && (replaceDiff >= oldRowDataCount || replaceDiff > oldPageSize)) {
  // Redraw if the new data completely overlaps the old data.
  redrawRequired = true;
}

So my question is why does it think that the new data completely overlaps the old data?

Am I using something incorrectly, is there a better way? This gets to be quite a slow down when it has to redraw thousands of rows that don't need to be redrawn.

Thanks, Will

2

2 Answers

1
votes

I think that, in this situation, the only way a CellTable can react to the call of the setVisibleRange() method is to redraw all rows.

You have just informed a CellTable that now it has to display new range (0-150 rows) instead of last (0-100 rows). There is no information that rows 0-100 remain unchanged and there is no need to redraw them.

The interesting thing is that you found the new rows are updated (rebuild) twice:

For instance, if I have 100 rows and then load 50 more it would build 0-150, and then rebuild 100-50

I've tried to reproduce this behavior in the smallest example:

public class ListDataProviderTest implements EntryPoint {

    private static final int ADD_COUNT = 10;

    private int nextVal = 0;

    public void onModuleLoad() {
        final CellTable<Integer> cellTable = new CellTable<Integer>();
        cellTable.addColumn(new TextColumn<Integer>() {
            @Override
            public String getValue(Integer object) {
                return object.toString();
            }});

        final ListDataProvider<Integer> listDataProvider = new ListDataProvider<Integer>();

        listDataProvider.addDataDisplay(cellTable);

        RootPanel.get().add(cellTable);
        RootPanel.get().add(new Button("Add more...", new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                List<Integer> list = listDataProvider.getList();
                for(int i = 0; i < ADD_COUNT; i++)
                    list.add(nextVal++);
                cellTable.setVisibleRange(0, list.size());
            }
        }));
    }
}

But I get all the rows updated once.

Can you confirm that this example reproduces the issue or provide one that is more accurate?

0
votes

AFAIK a CellTable always redraws all cells. This is how the renderer from the CellTable works. Although it always redraws all cells, it is in most times still faster than using a FlexTable and only updating a few cells.