mydomain
No ADS
No ADS

FlutterArtist Pagination Davi table Infinite Scroll Ex1

  1. Structure of the example
  2. Country61aShelf
  3. Country61aDaviTableItemsView
DAVI, short for “Data View”, is a Flutter library available on pub.dev that helps developers build complex data tables while remaining lightweight and easy to use. Davi is used in many FlutterArtist Demo examples, especially those related to displaying data tables.
FaDaviTable is a wrapper widget built around Davi, designed to simplify integration and interaction with FlutterArtist.
In this article, we will use FaDaviTable to build an infinite scrolling table. Whenever the user scrolls to the end of the table, additional data will be loaded automatically.
  • FlutterArtist Davi Table (***)
  • Download FlutterArtist Demo
  • FlutterArtist Grid ItemsView Infinite Scroll Example

1. Structure of the example

  • FlutterArtist Davi Table (***)

2. Country61aShelf

Country61aBlock is configured so that a maximum of 20 ITEM(s) are loaded per query.
country61a_shelf.dart
class Country61aShelf extends Shelf {
  @override
  ShelfStructure defineShelfStructure() {
    return ShelfStructure(
      filterModels: {},
      blocks: [
        Country61aBlock(
          name: Country61aBlock.blkName,
          description: null,
          config: BlockConfig(
            pageable: Pageable(pageSize: 20),
          ),
          filterModelName: null,
          formModel: null,
          childBlocks: [],
          itemSortCriteria: null,
        ),
      ],
    );
  }

  Country61aBlock findCountry61aBlock() {
    return findBlock(Country61aBlock.blkName) as Country61aBlock;
  }
}

3. Country61aDaviTableItemsView

When the user scrolls to the last row of the table, a Trailing widget will appear to indicate that the next set of data is being loaded.
_trailingWidget()
Widget? _trailingWidget() {
  PaginationInfo? pagination = block.paginationInfo;
  if (pagination == null) {
    return null;
  }
  if (pagination.currentPage < pagination.totalPages) {
    return Text("Loading...");
  }
  return null;
}
No ADS
You need to load the next page of data inside the onTrailingWidget() callback.
Future<void> _onTrailingWidget(bool visible) async {
  PaginationInfo? pagination = block.paginationInfo;
  if (pagination == null) {
    return;
  }
  if (visible && pagination.currentPage < pagination.totalPages) {
    // Delay 1 second to see Trailing widget longer.
    await Future.delayed(Duration(seconds: 1));
    await _loadMore();
  }
}
Future<void> _loadMore() async {
  await block.queryMore();
}
Below is the complete implementation of Country61aDaviTableItemsView, demonstrating how to build an infinite scrolling data table by combining Davi, FaDaviTable, and the FlutterArtist pagination mechanism.
country61a_davi_table_items_view.dart
class Country61aDaviTableItemsView extends BlockItemsView<Country61aBlock> {
  final Color? selectedColor = Colors.lightGreen.withAlpha(100);
  final Color? currentColor = Colors.lightGreen;
  final Color? hoverColor = Colors.greenAccent.withAlpha(30);
  final formatter = NumberFormat("###,###,###", "en_US");

  Country61aDaviTableItemsView({
    required super.block,
    super.key,
  }); 

  //
  // Davi Tutorials:
  // https://caduandrade.github.io/davi_flutter_demo/
  //
  @override
  Widget buildContent(BuildContext context) {
    return Container(
      padding: EdgeInsets.only(right: 0),
      child: DaviTheme(
        data: _daviThemeData(),
        child: FaDaviTable<String, CountryInfo>(
          items: block.items,
          getItemId: block.getItemId,
          sortRuleSide: SortRuleSide.blockSide,
          modelSettings: FaDaviTableModelSettings<CountryInfo>(
            ignoreDataComparators: true,
            sortingMode: SortingMode.disabled,
            columns: [
              DaviColumn(
                name: 'Image',
                resizable: false,
                width: 60,
                cellWidget: (param) {
                  return Center(
                    child: ImageUrlView(
                      imageUrl: param.data.imageUrl,
                      size: 30,
                      boxShape: BoxShape.rectangle,
                    ),
                  );
                },
              ),
              DaviColumn(
                name: 'Name In English',
                grow: 1,
                cellValue: (param) {
                  return param.data.nameInEnglish;
                },
              ),
              DaviColumn(
                name: 'Population',
                width: 100,
                cellAlignment: Alignment.centerRight,
                cellValue: (param) {
                  return param.data.population;
                },
                cellValueStringify: _formatNumber,
              ),
              DaviColumn(
                name: 'Area (Km2)',
                width: 100,
                cellAlignment: Alignment.centerRight,
                cellValue: (param) {
                  return param.data.area;
                },
                cellValueStringify: _formatNumber,
              ),
            ],
          ),
          visibleRowsCount: 10,
          // IMPORTANT: For Infinite Scroll Pagination.
          trailingWidget: _trailingWidget(),
          // IMPORTANT: For Infinite Scroll Pagination.
          onTrailingWidget: _onTrailingWidget,
          onRowTap: (CountryInfo countryInfo) {
            _setCountryAsCurrent(countryInfo);
          },
          rowColor: (param) {
            CountryInfo item = param.data;
            bool selected = block.isSelectedItem(item);
            bool current = block.isCurrentItem(item);
            if (current) {
              return currentColor;
            } else if (selected) {
              return selectedColor;
            }
            return null;
          },
        ),
      ),
    );
  }

  Widget? _trailingWidget() {
    PaginationInfo? pagination = block.paginationInfo;
    if (pagination == null) {
      return null;
    }
    if (pagination.currentPage < pagination.totalPages) {
      return Text("Loading...");
    }
    return null;
  }

  Future<void> _onTrailingWidget(bool visible) async {
    PaginationInfo? pagination = block.paginationInfo;
    if (pagination == null) {
      return;
    }
    if (visible && pagination.currentPage < pagination.totalPages) {
      // Delay 1 second to see Trailing widget longer.
      await Future.delayed(Duration(seconds: 1));
      await _loadMore();
    }
  }

  Future<void> _loadMore() async {
    await block.queryMore();
  }

  String _formatNumber(dynamic value) {
    return formatter.format(value);
  }

  DaviThemeData _daviThemeData() {
    return DaviThemeData(
      columnDividerThickness: 0.4,
      columnDividerFillHeight: true,
      decoration: BoxDecoration(
        border: Border.all(
          width: 0.2,
          color: Colors.grey,
        ),
      ),
      scrollbar: TableScrollbarThemeData(
        horizontalOnlyWhenNeeded: true,
        verticalOnlyWhenNeeded: true,
      ),
      header: HeaderThemeData(),
      headerCell: HeaderCellThemeData(
        padding: EdgeInsets.all(5),
        height: 30,
      ),
      row: RowThemeData(
        dividerThickness: 0.4,
        fillHeight: true,
        color: null,
        hoverBackground: (int row) {
          if (block.isCurrentIndex(row)) {
            return currentColor;
          } else if (block.isSelectedIndex(row)) {
            return selectedColor;
          } else {
            return hoverColor;
          }
        },
      ),
      cell: CellThemeData(
        padding: EdgeInsets.all(5),
        contentHeight: 30,
      ),
    );
  }

  Future<void> _setCountryAsCurrent(CountryInfo countryInfo) async {
    FlutterArtist.codeFlowLogger.addMethodCall(
      ownerClassInstance: this,
      currentStackTrace: StackTrace.current,
      parameters: {"countryInfo": countryInfo},
    );
    //
    await block.refreshItemAndSetAsCurrent(
      item: countryInfo,
    );
  }
}
No ADS
No ADS