Why Flutter SfDataGrid sorting just renders sorted rows and no changes in datasource?

286 Views Asked by At

Im trying to use build-in sorting in my SfDataGrid. It works fine and flutter rerenders and show me sorted table, but when im trying to get cell value in table its bring me past(not sorted) value of cell.

So I want to not only render the sorted list but also sort the data source as well.

 return FutureBuilder(
    future: _portfolioDataSource.loadAndBuildPortfolioData(),
    builder: (ctx, snapshot) {
      asyncSnapshotErrorHandler(snapshot);
      if (snapshot.connectionState == ConnectionState.done) {
        return SfDataGridTheme(
            data: SfDataGridThemeData(
                headerColor: Color.fromRGBO(243, 243, 250, 1)),
            child: SfDataGrid(
                onSelectionChanged: _portfolioDataSource.isEntitiesEmpty
                    ? null
                    : _onSelectionChanged,
                gridLinesVisibility: GridLinesVisibility.horizontal,
                headerGridLinesVisibility: GridLinesVisibility.horizontal,
                highlightRowOnHover: true,
                source: _portfolioDataSource,
                frozenColumnsCount: _portfolioDataSource.isEntitiesEmpty
                    ? 0
                    : widget.frozenColumnsCount,
                columnWidthMode: ColumnWidthMode.none,
                allowPullToRefresh: true,
                allowSorting: false,
                allowMultiColumnSorting: false,
                showSortNumbers: true,
                loadMoreViewBuilder:
                    (BuildContext context, LoadMoreRows loadMoreRows) {
                  bool showIndicator = false;
                  return StatefulBuilder(builder:
                      (BuildContext context, StateSetter setState) {
                    if (showIndicator) {
                      return Container(
                          height: 60.0,
                          width: double.infinity,
                          alignment: Alignment.center,
                          decoration: BoxDecoration(
                              color: Colors.white,
                              border: BorderDirectional(
                                  top: BorderSide(
                                      width: 1.0,
                                      color:
                                          Color.fromRGBO(0, 0, 0, 0.26)))),
                          child: CircularProgressIndicator(
                              valueColor: AlwaysStoppedAnimation(
                            Color.fromRGBO(18, 183, 106, 1),
                          )));
                    } else {
                      return Container(
                          height: 60.0,
                          width: double.infinity,
                          alignment: Alignment.center,
                          decoration: BoxDecoration(
                              color: Colors.white,
                              border: BorderDirectional(
                                  top: BorderSide(
                                      width: 1.0,
                                      color:
                                          Color.fromRGBO(0, 0, 0, 0.26)))),
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Container(
                                  margin:
                                      EdgeInsets.symmetric(horizontal: 20),
                                  height: 36.0,
                                  width: 142.0,
                                  child: TextButton(
                                      style: ButtonStyle(
                                          backgroundColor:
                                              MaterialStateProperty.all(
                                        Color.fromRGBO(18, 183, 106, 1),
                                      )),
                                      child: Text('LOAD MORE',
                                          style: TextStyle(
                                              color: Colors.white)),
                                      onPressed: () async {
                                        _onSelectionChanged([], []);
                                        if (context is StatefulElement &&
                                            context.state.mounted) {
                                          setState(() {
                                            print(
                                                widget.selectedInstanceIds);
                                            showIndicator = true;
                                          });
                                        }
                                        await loadMoreRows();
                                        if (context is StatefulElement &&
                                            context.state.mounted) {
                                          setState(() {
                                            showIndicator = false;
                                          });
                                        }
                                      })),
                              Container(
                                  margin:
                                      EdgeInsets.symmetric(horizontal: 20),
                                  height: 36.0,
                                  width: 142.0,
                                  child: TextButton(
                                      style: ButtonStyle(
                                          backgroundColor:
                                              MaterialStateProperty.all(
                                        Color.fromRGBO(18, 183, 106, 1),
                                      )),
                                      child: Text('LOAD ALL',
                                          style: TextStyle(
                                              color: Colors.white)),
                                      onPressed: () async {
                                        if (context is StatefulElement &&
                                            context.state.mounted) {
                                          setState(() {
                                            showIndicator = true;
                                          });
                                        }
                                        await _portfolioDataSource
                                            .loadAllRows();

                                        if (context is StatefulElement &&
                                            context.state.mounted) {
                                          setState(() {
                                            showIndicator = false;
                                          });
                                        }
                                      })),
                            ],
                          ));
                    }
                  });
                },

And DataSource

    import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
import 'package:zwe_spmis_mobile/models/controls/portfolio-control/portfolio_configs.dart';
import 'package:zwe_spmis_mobile/services/portfolio_service.dart';
import '../../../services/api/entity_search_service.dart';
import '../../../services/provider/service_provider.dart';
import '../../../utils/entity_helpers/filter/filter_builder.dart';
import '../../../zwe_icons_icons.dart';
import '../../entity.dart';
import '../../portfolio_items_state.dart';

class PortfolioDataSource extends DataGridSource {
  final List<dynamic> _entities = [];
  List<int> downloadedItemIds = [];
  List<DataGridRow> _dataGridRows = [];
  PortfolioService _portfolioService = new PortfolioService();
  PortfolioItemsState _portfolioItemsState;
  final FilterBuilder _filter;
  final String _categorySystemName;
  final Function buildDataGridRows;
  final highlitedFieldSystemName;
  String? bulkAction;
  int pageNumber = 0;
  int countPerPage = 20;
  String sortFields = "DateUpdated";
  bool isEntitiesEmpty = false;
  EntitySearchService _offlineEntitySearchService =
      ServiceProvider.getOfflineContext().getEntitySearchService();

  PortfolioDataSource(
      this._portfolioItemsState,
      this._filter,
      this._categorySystemName,
      this.buildDataGridRows,
      this.highlitedFieldSystemName,
      this.countPerPage,
      this.pageNumber,
      {this.bulkAction: null});

  Future<void> handleLoadMoreRows() async {
    this.pageNumber++;
    await loadMoreAndBuildPortfolioData();
  }

  Future<void> loadAllRows() async {
    this.pageNumber = 0;
    this.countPerPage = 500;
    await loadAndBuildPortfolioData();
    this.pageNumber = 25;
    this.countPerPage = 20;
  }

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

  @override
  DataGridRowAdapter? buildRow(DataGridRow row) {
    TextStyle? getTextStyle(DataGridCell<dynamic> dataGridCell) {
      return TextStyle(
          color: dataGridCell.columnName == ''
              ? Color.fromRGBO(19, 180, 105, 1)
              : null);
    }

    return DataGridRowAdapter(
        cells: row.getCells().map<Widget>((dataGridCell) {
      return Container(
          alignment: (dataGridCell.columnName == 'id')
              ? Alignment.centerRight
              : Alignment.centerLeft,
          padding: const EdgeInsets.symmetric(horizontal: 16.0),
          child: dataGridCell.columnName == 'actions'
              ? RichText(
                  text: TextSpan(
                    children: [
                      WidgetSpan(
                          child: (dataGridCell.value.toString() == 'Download')
                              ? Icon(
                                  ZweIcons.download,
                                  size: 20,
                                  color: Color.fromRGBO(19, 180, 105, 1),
                                )
                              : (dataGridCell.value.toString() == 'Submit')
                                  ? RichText(
                                      text: TextSpan(
                                        style: TextStyle(
                                            color:
                                                Color.fromRGBO(19, 180, 105, 1),
                                            fontWeight: FontWeight.w900),
                                        children: [
                                          WidgetSpan(
                                            child: Icon(
                                              Icons.upload,
                                              size: 20,
                                              color: Color.fromRGBO(
                                                  19, 180, 105, 1),
                                            ),
                                          ),
                                        ],
                                      ),
                                    )
                                  : Text('')),
                      TextSpan(
                        style: dataGridCell.value.toString() == 'Downloaded' ||
                                dataGridCell.value.toString() == 'Delete'
                            ? TextStyle(
                                color: Color.fromRGBO(19, 180, 105, 1),
                                fontWeight: FontWeight.w900)
                            : TextStyle(color: Color.fromRGBO(19, 180, 105, 1)),
                        text: dataGridCell.value.toString(),
                      ),
                    ],
                  ),
                )
              : dataGridCell.columnName == 'sync'
                  ? RichText(
                      text: TextSpan(
                        children: [
                          WidgetSpan(
                            child: Icon(
                              Icons.upload,
                              size: 20,
                              color: Color.fromRGBO(19, 180, 105, 1),
                            ),
                          ),
                          TextSpan(
                            style: TextStyle(
                                color: Color.fromRGBO(19, 180, 105, 1)),
                            text: "Submit",
                          ),
                        ],
                      ),
                    )
                  : Text(
                      dataGridCell.value.toString(),
                      overflow: TextOverflow.ellipsis,
                      style: TextStyle(
                          color: dataGridCell.columnName ==
                                  this.highlitedFieldSystemName
                              ? Color.fromRGBO(44, 121, 231, 1)
                              : dataGridCell.columnName == 'actions'
                                  ? Color.fromRGBO(19, 180, 105, 1)
                                  : null),
                    ));
    }).toList());
  }

  addItem(Entity ent, String? bulkAction) {
    _entities.add(ent);
    _dataGridRows = buildDataGridRows(_entities, bulkAction);
    notifyListeners();
  }

  Future<List<int>> loadDownloadedItemIds() {
    return _offlineEntitySearchService.loadAllEntityIds(_categorySystemName);
  }

  removeItem(int entityInstanceId) {
    this.downloadedItemIds.remove(entityInstanceId);
    this
        ._entities
        .removeWhere((element) => element['instanceId'] == entityInstanceId);
    _dataGridRows.removeWhere((element) =>
        element.getCells()[element.getCells().length - 1].value ==
        entityInstanceId);
  }

  Future<List<Map<String, dynamic>>> loadCreatedItems() {
    return _offlineEntitySearchService.loadEntitiesByInstanceIds(
        this._categorySystemName,
        downloadedItemIds.where((element) => element < 0).toList());
  }

 
  Future<void> loadAndBuildPortfolioData() async {
    _entities.length = 0;
    _entities.addAll(await loadCreatedItems());
    this.downloadedItemIds = await loadDownloadedItemIds();
    if (this.bulkAction == 'Download') {
      _portfolioItemsState = PortfolioItemsState.NOT_DOWNLOADED;
    }
    await _portfolioService
        .loadEntitiesByFilter(
            _categorySystemName,
            _portfolioItemsState,
            sortFields,
            countPerPage,
            pageNumber,
            _filter,
            serializationFields[_categorySystemName])
        .then((List<dynamic> value) {
      _entities.addAll(value);
        _dataGridRows =
            buildDataGridRows(_entities, downloadedItemIds, bulkAction);
        isEntitiesEmpty = (_entities.length == 0);
        notifyListeners();
    });
  }
}
1

There are 1 best solutions below

0
On

You can get the sorted row collection from the DataGridSource.effectiveRows property. It holds the sorted collection if the sorting is applied in DataGrid.

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  List<Employee> _employees = <Employee>[];
  late EmployeeDataSource _employeeDataSource;

  @override
  void initState() {
    super.initState();
    _employees = _getEmployeeData();
    _employeeDataSource = EmployeeDataSource(employeeData: _employees);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter DataGrid')),
      body: Column(
        children: [
          Container(
            margin: const EdgeInsets.all(30),
            child: ElevatedButton(
                onPressed: (() {
                  // You can get a sorted collection from effectiveRows property.
                  for (var details in _employeeDataSource.effectiveRows) {
                    print(details.getCells()[0].value);
                  }
                }),
                child: const Text('Get Sorted Collection')),
          ),
          Expanded(
            child: SfDataGrid(
              source: _employeeDataSource,
              allowSorting: true,
              columnWidthMode: ColumnWidthMode.fill,
              columns: <GridColumn>[
                GridColumn(
                    columnName: 'ID',
                    label: Container(
                        padding: const EdgeInsets.all(8.0),
                        alignment: Alignment.center,
                        child: const Text('ID'))),
                GridColumn(
                    columnName: 'Name',
                    label: Container(
                        padding: const EdgeInsets.all(8.0),
                        alignment: Alignment.center,
                        child: const Text('Name'))),
                GridColumn(
                    columnName: 'Designation',
                    label: Container(
                        padding: const EdgeInsets.all(8.0),
                        alignment: Alignment.center,
                        child: const Text('Designation'))),
                GridColumn(
                    columnName: 'Salary',
                    label: Container(
                        padding: const EdgeInsets.all(8.0),
                        alignment: Alignment.center,
                        child: const Text('Salary'))),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class EmployeeDataSource extends DataGridSource {
  EmployeeDataSource({required List<Employee> employeeData}) {
    _employeeData = employeeData
        .map<DataGridRow>((Employee e) => DataGridRow(cells: <DataGridCell>[
              DataGridCell<int>(columnName: 'ID', value: e.id),
              DataGridCell<String>(columnName: 'Name', value: e.name),
              DataGridCell<String>(
                  columnName: 'Designation', value: e.designation),
              DataGridCell<int>(columnName: 'Salary', value: e.salary),
            ]))
        .toList();
  }

  List<DataGridRow> _employeeData = <DataGridRow>[];

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

  @override
  DataGridRowAdapter buildRow(DataGridRow row) {
    return DataGridRowAdapter(
        cells: row.getCells().map<Widget>((DataGridCell cell) {
      return Container(
        alignment: Alignment.center,
        padding: const EdgeInsets.all(8.0),
        child: Text(cell.value.toString()),
      );
    }).toList());
  }
}

class Employee {
  Employee(this.id, this.name, this.designation, this.salary);
  final int id;
  final String name;
  final String designation;
  final int salary;
}

List<Employee> _getEmployeeData() {
  return <Employee>[
    Employee(10001, 'James', 'Manager', 90000),
    Employee(10002, 'Kathryn', 'Project Lead', 75000),
    Employee(10003, 'Lara', 'Developer', 45000),
    Employee(10004, 'Michael', 'Designer', 37000),
    Employee(10005, 'Martin', 'Developer', 43000),
  ];
}