Copied RSS Feed

Flutter

How to Perform Lazy Loading in Flutter Data Table

The Syncfusion Flutter DataGrid (data table) widget provides support to load data lazily with an interactive view when the grid reaches its maximum offset while scrolling down. In this blog, we are going to discuss how to enable the load-more feature in Flutter DataGrid and perform the lazy loading of data fetched from Firebase. Before getting into the steps, go through the overview of connecting Firebase to your Flutter application.

Note: In this blog, we use Firebase data as an example only. We are not going to provide the Firebase connectivity files here.

Dependency package

Include the Syncfusion Flutter DataGrid and Firebase package dependencies in the pubspec.yaml file of your project using the following code.

firebase_core: ^1.0.2
cloud_firestore: ^1.0.3
syncfusion_flutter_datagrid: ^19.1.54-beta.1

Create a model data class

Create an employee class to cast and store the Firebase data in your project.

Refer to the following code example.

import 'package:cloud_firestore/cloud_firestore.dart';

class Employee {
  Employee(this.employeeID, this.employeeName, this.designation,
      this.salary,
      {this.reference});

  double employeeID;

  String employeeName;

  String designation;

  double salary;

  DocumentReference? reference;

  factory Employee.fromSnapshot(DocumentSnapshot snapshot) {
    Employee newEmployee = Employee.fromJson(snapshot.data()!);
    newEmployee.reference = snapshot.reference;
    return newEmployee;
  }

  factory Employee.fromJson(Map<String, dynamic> json) =>
      _employeeFromJson(json);

  Map<String, dynamic> toJson() => _employeeToJson(this);

  @override
  String toString() => 'employeeName $employeeName';
}

Employee _employeeFromJson(Map<String, dynamic> data) {
  return Employee(
    data['employeeID'],
    data['employeeName'],
    data['designation'],
    data['salary'],
  );
}

Map<String, dynamic> _employeeToJson(Employee instance) {
  return {
    'employeeID' : instance.employeeID,
    'employeeName': instance.employeeName,
    'designation': instance.designation,
    'salary': instance.salary,
  };
}

Create a DataGridSource class and initialize the Firebase

Please follow these steps to create a DataGridSource and initialize the Firebase:

Step 1: Create DataGridSource

First, create a DataGridSource class, which is required for the SfDataGrid. With this class, we are going to obtain the row data.

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';

import '../model/employee.dart';

class EmployeeDataGridSource extends DataGridSource {
 
  List<DataGridRow> dataGridRows = [];

  List<Employee> employees = [];


  @override
  List<DataGridRow> get rows => dataGridRows;

  @override
  DataGridRowAdapter? buildRow(DataGridRow row) {
    return DataGridRowAdapter(
        cells: row.getCells().map<Widget>((dataGridCell) {
      if (dataGridCell.columnName == 'employeeID' ||
          dataGridCell.columnName == 'salary') {
        return Container(
          alignment: Alignment.centerRight,
          padding: EdgeInsets.symmetric(horizontal: 16.0),
          child: Text(
              (dataGridCell.columnName == 'salary') ? NumberFormat.currency(locale: 'en_US', symbol: '\

Step 2: Initialize Firebase

Then, we have to initialize Firebase in the main() method to access the Firebase services.

import 'package:firebase_core/firebase_core.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(SfDataGridLoadMoreApp());
}

Step 3: Fetch data from cloud

Now, initialize the Firebase collection inside the DataGridSource class to fetch data from the cloud.

import 'package:cloud_firestore/cloud_firestore.dart';

class EmployeeDataGridSource extends DataGridSource {
  EmployeeDataGridSource() {
    collection = FirebaseFirestore.instance.collection('employees');
  }

  late CollectionReference collection;
}

Enable the lazy-loading feature in DataGrid

Now, let’s enable the lazy-loading feature in the  Flutter DataGrid:

Step 1: Import packages

First, import the Flutter DataGrid and Firebase repository packages in the main.dart file using the following code.

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_datagrid_loadmore/repositories/employee_repository.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';

Step 2: Implement lazy loading

We can perform lazy loading by using either of the following ways in the Flutter data table:

In this blog, we are going to lazy load data using the infinite-scrolling feature in the DataGrid:

  • Use the loadMoreViewBuilder callback, which will be called when the DataGrid reaches its maximum vertical offset.
  • In the loadMoreViewBuilder callback, provide the loadMoreRows callback as a parameter.
  • Using the loadMoreRows callback, you can load data lazily.

Refer to the following code example.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_datagrid_loadmore/repositories/employee_repository.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';

class SfDataGridLoadMoreApp extends StatelessWidget {
  final EmployeeDataGridSource employeeDataGridSource =
      EmployeeDataGridSource();

  SfDataGridLoadMoreApp() {
    employeeDataGridSource.loadMoreStream();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text('DataGrid Lazy Loading'),
        ),
        body: SfDataGrid(
          source: employeeDataGridSource,
          columnWidthMode: ColumnWidthMode.fill,
          columns: [
            GridTextColumn(
                columnName: 'employeeID',
                label: Container(
                  padding: EdgeInsets.symmetric(horizontal: 16.0),
                  child: Text(
                    'ID',
                    overflow: TextOverflow.ellipsis,
                  ),
                  alignment: Alignment.centerRight,
                )),
            GridTextColumn(
                columnName: 'employeeName',
                label: Container(
                    padding: EdgeInsets.symmetric(horizontal: 16.0),
                    child: Text(
                      'Name',
                      overflow: TextOverflow.ellipsis,
                    ),
                    alignment: Alignment.centerLeft)),
            GridTextColumn(
                columnName: 'designation',
                label: Container(
                    padding: EdgeInsets.symmetric(horizontal: 16.0),
                    child: Text(
                      'Role',
                      overflow: TextOverflow.ellipsis,
                    ),
                    alignment: Alignment.centerLeft)),
            GridTextColumn(
                columnName: 'salary',
                label: Container(
                    padding: EdgeInsets.symmetric(horizontal: 16.0),
                    child: Text(
                      'Salary',
                      overflow: TextOverflow.ellipsis,
                    ),
                    alignment: Alignment.centerRight)),
          ],
          loadMoreViewBuilder: loadMoreInfiniteBuilder,
        ),
      ),
    );
  }

  /// Hook this builder for applying the infinite scrolling support
  Widget loadMoreInfiniteBuilder(
      BuildContext context, LoadMoreRows loadMoreRows) {
    Future<String> loadRows() async {
      await loadMoreRows();
      return Future<String>.value('Completed');
    }

    return FutureBuilder<String>(
        initialData: 'loading',
        future: loadRows(),
        builder: (context, snapShot) {
          if (snapShot.data == 'loading') {
            return Container(
                height: 60.0,
                width: double.infinity,
                decoration: BoxDecoration(
                    color: Colors.white,
                    border: BorderDirectional(
                        top: BorderSide(
                            width: 1.0, color: Color.fromRGBO(0, 0, 0, 0.26)))),
                alignment: Alignment.center,
                child: CircularProgressIndicator(
                    valueColor: AlwaysStoppedAnimation(Colors.deepPurple)));
          } else {
            return SizedBox.fromSize(size: Size.zero);
          }
        });
  }
}

Step 3: Implement busy indicator

  • Then, override the handleLoadMoreRows property in the DataGridSource class to load more data lazily. This method will be called whenever the loadMoreRows callback is called from the loadMoreViewBuilder callback.
  • You can use await to show a busy indicator while fetching data from Firebase. Here, we have delayed 500 ms manually to show the busy indicator for example purposes.

Refer to the following code example.

class EmployeeDataGridSource extends DataGridSource {

  static const double perPage = 100;

  List<Employee> employees = [];

  void addDataGridRow(Employee data) {
    dataGridRows.add(DataGridRow(cells: [
      DataGridCell<double>(columnName: 'employeeID', value: data.employeeID),
      DataGridCell<String>(
          columnName: 'employeeName', value: data.employeeName),
      DataGridCell<String>(columnName: 'designation', value: data.designation),
      DataGridCell<double>(columnName: 'salary', value: data.salary),
    ]));
  }

  Future loadMoreDataFromStream() async {
    final stream = collection
        .where('employeeID',
            isGreaterThan:
                employees.isEmpty ? 1000.0 : employees.last.employeeID,
            isLessThan: employees.isEmpty
                ? 1000.0 + perPage
                : employees.last.employeeID + perPage)
        .snapshots();

    stream.listen((snapShot) async {
      await Future.forEach(snapShot.docs, (DocumentSnapshot element) {
        final Employee data = Employee.fromSnapshot(element);
        if (!employees
            .any((element) => element.employeeID == data.employeeID)) {
          employees.add(data);
          addDataGridRow(data);
        }
      });

      updateDataGridDataSource();
    });
  }

  @override
  Future<void> handleLoadMoreRows() async {
    /// Perform delay to load the data to show the loading indicator if required.
    await Future.delayed(const Duration(milliseconds: 500), () {
      loadMoreDataFromStream();
    });
  }

  void updateDataGridDataSource() {
    notifyListeners();
  }
}
Lazy Loading in Flutter Data Table via Infinite Scrolling
Lazy Loading in Flutter Data Table Using Load More Button

Resource

For more information, refer to Perform lazy loading in Flutter Data Table (SfDataGrid) demo.

Conclusion

In this blog post, we have seen the steps to lazy load data in the Syncfusion Flutter DataGrid (data table) while fetching data from Firebase. With this, you can load only the required data at once and load the remaining data on demand. This will enhance your productivity and reduce the loading time, too.

Syncfusion DataGrid is also available in our Blazor, ASP.NET (Core, MVC, WebForms), Angular, React, Vue, Xamarin, Flutter, UWP, WinForms, WPF, and WinUI platforms. Use them to build powerful applications!

For existing customers, the new version is available for download from the License and Downloads page. If you are not yet a Syncfusion customer, you can try our 30-day free trial to check out our available features. Also, try our samples from this GitHub location.

You can contact us through our support forumDirect-Trac, or feedback portal. We are always happy to assist you!

Related blogs

).format(dataGridCell.value).toString() :
dataGridCell.value.toInt().toString(),
overflow: TextOverflow.ellipsis,
),
);
}
return Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Text(dataGridCell.value.toString(),
overflow: TextOverflow.ellipsis),
);
}).toList());
}

void updateDataGridDataSource() {
notifyListeners();
}
}

Step 2: Initialize Firebase

Then, we have to initialize Firebase in the main() method to access the Firebase services.

 

Step 3: Fetch data from cloud

Now, initialize the Firebase collection inside the DataGridSource class to fetch data from the cloud.

 

Enable the lazy-loading feature in DataGrid

Now, let’s enable the lazy-loading feature in the  Flutter DataGrid:

Step 1: Import packages

First, import the Flutter DataGrid and Firebase repository packages in the main.dart file using the following code.

 

Step 2: Implement lazy loading

We can perform lazy loading by using either of the following ways in the Flutter data table:

In this blog, we are going to lazy load data using the infinite-scrolling feature in the DataGrid:

  • Use the loadMoreViewBuilder callback, which will be called when the DataGrid reaches its maximum vertical offset.
  • In the loadMoreViewBuilder callback, provide the loadMoreRows callback as a parameter.
  • Using the loadMoreRows callback, you can load data lazily.

Refer to the following code example.

 

Step 3: Implement busy indicator

  • Then, override the handleLoadMoreRows property in the DataGridSource class to load more data lazily. This method will be called whenever the loadMoreRows callback is called from the loadMoreViewBuilder callback.
  • You can use await to show a busy indicator while fetching data from Firebase. Here, we have delayed 500 ms manually to show the busy indicator for example purposes.

Refer to the following code example.

 
Lazy Loading in Flutter Data Table via Infinite Scrolling
Lazy Loading in Flutter Data Table Using Load More Button

Resource

For more information, refer to Perform lazy loading in Flutter Data Table (SfDataGrid) demo.

Conclusion

In this blog post, we have seen the steps to lazy load data in the Syncfusion Flutter DataGrid (data table) while fetching data from Firebase. With this, you can load only the required data at once and load the remaining data on demand. This will enhance your productivity and reduce the loading time, too.

Syncfusion DataGrid is also available in our Blazor, ASP.NET (Core, MVC, WebForms), Angular, React, Vue, Xamarin, Flutter, UWP, WinForms, WPF, and WinUI platforms. Use them to build powerful applications!

For existing customers, the new version is available for download from the License and Downloads page. If you are not yet a Syncfusion customer, you can try our 30-day free trial to check out our available features. Also, try our samples from this GitHub location.

You can contact us through our support forumDirect-Trac, or feedback portal. We are always happy to assist you!

Related blogs

Meet the Author

Balasubramani Sundaram

Balasubramani Sundaram is a software engineer at Syncfusion He has been a Xamarin and Flutter developer since 2018 and works with custom control for cross-platform applications. He provides support for DataGrid control. He is eager to learn new technologies and loves blogging.