bosskmk / pluto_grid

PlutoGrid is a dataGrid for flutter that can be controlled by the keyboard on desktop and web. Of course, it works well on Android and IOS.

Home Page:https://pluto.weblaze.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

PlutoGrid isn't refreshing

hamzaj9 opened this issue · comments

I have an issue with PlutoGrid.

I have DefaultTabController with tabBarView. one of the tabs containing PlutoGrid.
every time I switch between tabs, the grid is refreshing just fine.
but when I select a row. then go to other tab and go back to grid tab. the tab stop refreshing.
one bad fix I found: add FocusScope.of(this.context).unfocus(); inside onSelected, but the problem here is every time i select it will refresh the grid.

this is a sample code:

import 'package:flutter/material.dart';
import 'package:pluto_grid/pluto_grid.dart';
import 'dart:async';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: DefaultTabController(
      initialIndex: 0,
      length: 2,
      child: Scaffold(
        appBar: PreferredSize(
          preferredSize: Size.fromHeight(70.0), // here the desired height
          child: FocusScope(
            canRequestFocus: false,
            child: AppBar(
              shape: const Border(
                  bottom:
                      BorderSide(color: Colors.grey)),
              title: const SizedBox(
                width: 400,
                child: TabBar(
                  indicatorColor: Colors.blue,
                  indicatorWeight: 4,
                  tabs: [
                    Tab(
                      height: 66,
                      icon: Text(
                        "locations",
                      ),
                    ),
                    Tab(
                      height: 66,
                      icon: Text(
                        "locations2",
                      ),
                    ),
                  ],
                ),
              ),
              elevation: 0,
              toolbarHeight: 70,
            ),
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            Container(color: Colors.white,
            child: FocusTraversalGroup(
              policy: WidgetOrderTraversalPolicy(),
              child: LocationsTab(),
                ),
            ),
            Container(color: Colors.white,
            child: FocusTraversalGroup(
              policy: WidgetOrderTraversalPolicy(),
              child: LocationsTab(),
                ),
            )
          ],
        ),
      )
      )
    );
  }
}


class LocationsTab extends StatefulWidget {
  @override
  State<LocationsTab> createState() => _LocationsTabState();
}

class _LocationsTabState extends State<LocationsTab> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(12),
      child: Row(
        children: [
          Expanded(flex: 8, child: Padding(padding: const EdgeInsets.only(left: 6), child: LocationGrid())),
          const Expanded(flex: 4, child: Padding(padding: const EdgeInsets.only(left: 6), child: Text("Hello")))
        ]
      )
    );
  }
}

class LocationGrid extends StatefulWidget {
  @override
  State<LocationGrid> createState() => _LocationGridState();
}

class _LocationGridState extends State<LocationGrid> {

  final List<PlutoColumn> columns = [];
  final List<PlutoRow> rows = [];
  static PlutoGridStateManager? stateManager = null;

  void ReloadLocations() async {
    stateManager?.setShowLoading(true);
    rows.clear();
    
    rows.add(PlutoRow(
      cells: {
        "id" : PlutoCell(value: 1),
        "name" : PlutoCell(value: "New York"),
      },
    ));
    rows.add(PlutoRow(
      cells: {
        "id" : PlutoCell(value: 2),
        "name" : PlutoCell(value: "Tokyo"),
      },
    ));
    stateManager?.removeAllRows(notify: false);
    stateManager?.appendRows(rows);
    stateManager?.setShowLoading(false, notify: true);
  }

  @override
  Widget build(BuildContext context) {
    if(columns.isEmpty){
      columns.add(PlutoColumn(
        title: "#",
        field: "id",
        readOnly: true,
        type: PlutoColumnType.number(format: '#'),
        enableRowDrag: false,
        enableColumnDrag: false,
        enableSorting: false,
        enableContextMenu: false,
        enableDropToResize: false,
        enableFilterMenuItem: false
      ));
      columns.add(PlutoColumn(
        title: "Location",
        field: "name",
        readOnly: true,
        type: PlutoColumnType.text(),
        enableRowDrag: false,
        enableColumnDrag: false,
        enableSorting: false,
        enableContextMenu: false,
        enableDropToResize: false,
      ));
    }

    Timer(const Duration(seconds:3), () => ReloadLocations());
    PlutoGrid grid = PlutoGrid(
      columns: columns,
      rows: [],
      configuration: PlutoGridConfiguration(
        columnSize: const PlutoGridColumnSizeConfig(
          autoSizeMode: PlutoAutoSizeMode.scale,
          resizeMode: PlutoResizeMode.normal,
        ),
        style: PlutoGridStyleConfig(rowHeight: 30, oddRowColor: Colors.cyan[50], evenRowColor: Colors.white),
        scrollbar: const PlutoGridScrollbarConfig(isAlwaysShown: true)
      ),
      onSelected: (PlutoGridOnSelectedEvent event){
        
      },
      onLoaded: (PlutoGridOnLoadedEvent event) {
        stateManager = event.stateManager;
        stateManager!.notifyListeners();
        stateManager!.setShowLoading(true);
        PlutoGridSelectingMode gridSelectingMode = PlutoGridSelectingMode.horizontal;
        stateManager!.setSelectingMode(gridSelectingMode);
        stateManager!.setShowColumnFilter(true);
      },
      mode: PlutoGridMode.selectWithOneTap,
    );

    stateManager?.notifyListeners();

    return grid;
  }
}

note this only to let you see the bug. just select a row. and go to another tab and back to the first tab. it will not refresh.

Do not add columns or rows in the build method.
To add a row or column, please refer to the link below.

https://pluto.weblaze.dev/add-and-remove-columns-and-rows

@bosskmk how this will help in my issue !!
if i select the row, it will never refresh the grid after switching tabs !

@bosskmk did you try my code?
if not, kindly just give it a try

@bosskmk i tried this:

import 'package:flutter/material.dart';
import 'package:pluto_grid/pluto_grid.dart';
import 'dart:async';
import 'package:faker/faker.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: DefaultTabController(
      initialIndex: 0,
      length: 2,
      child: Scaffold(
        appBar: PreferredSize(
          preferredSize: Size.fromHeight(70.0), // here the desired height
          child: FocusScope(
            canRequestFocus: false,
            child: AppBar(
              shape: const Border(
                  bottom:
                      BorderSide(color: Colors.grey)),
              title: const SizedBox(
                width: 400,
                child: TabBar(
                  indicatorColor: Colors.blue,
                  indicatorWeight: 4,
                  tabs: [
                    Tab(
                      height: 66,
                      icon: Text(
                        "locations",
                      ),
                    ),
                    Tab(
                      height: 66,
                      icon: Text(
                        "locations2",
                      ),
                    ),
                  ],
                ),
              ),
              elevation: 0,
              toolbarHeight: 70,
            ),
          ),
        ),
        body: TabBarView(
          children: <Widget>[
            Container(color: Colors.white,
            child: FocusTraversalGroup(
              policy: WidgetOrderTraversalPolicy(),
              child: LocationsTab(),
                ),
            ),
            Container(color: Colors.white,
            child: FocusTraversalGroup(
              policy: WidgetOrderTraversalPolicy(),
              child: LocationsTab(),
                ),
            )
          ],
        ),
      )
      )
    );
  }
}




class LocationsTab extends StatefulWidget {
  @override
  State<LocationsTab> createState() => _LocationsTabState();
}

class _LocationsTabState extends State<LocationsTab> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(12),
      child: Row(
        children: [
          Expanded(flex: 8, child: Padding(padding: const EdgeInsets.only(left: 6), child: LocationGrid())),
          const Expanded(flex: 4, child: Padding(padding: const EdgeInsets.only(left: 6), child: Text("Hello")))
        ]
      )
    );
  }
}

class DummyData {
  late List<PlutoColumn> columns;

  late List<PlutoRow> rows;

  DummyData(
    int columnLength,
    int rowLength, {
    List<int> leftFrozenColumnIndexes = const [],
    List<int> rightFrozenColumnIndexes = const [],
  }) {
    var faker = Faker();

    columns = List<int>.generate(columnLength, (index) => index).map((i) {
      return PlutoColumn(
        title: faker.food.cuisine(),
        field: i.toString(),
        readOnly: [1, 3, 5].contains(i),
        type: (int i) {
          if (i == 0) {
            return PlutoColumnType.number();
          } else if (i == 1) {
            return PlutoColumnType.number();
          } else if (i == 2) {
            return PlutoColumnType.text();
          } else if (i == 3) {
            return PlutoColumnType.text();
          } else if (i == 4) {
            return PlutoColumnType.select(<String>['One', 'Two', 'Three']);
          } else if (i == 5) {
            return PlutoColumnType.select(<String>['One', 'Two', 'Three']);
          } else if (i == 6) {
            return PlutoColumnType.date();
          } else if (i == 7) {
            return PlutoColumnType.time();
          } else {
            return PlutoColumnType.text();
          }
        }(i),
        frozen: (int i) {
          if (leftFrozenColumnIndexes.contains(i)) {
            return PlutoColumnFrozen.start;
          }
          if (rightFrozenColumnIndexes.contains(i)) {
            return PlutoColumnFrozen.end;
          }
          return PlutoColumnFrozen.none;
        }(i),
      );
    }).toList();

    rows = rowsByColumns(length: rowLength, columns: columns);
  }

  static dynamic valueByColumnType(PlutoColumn column) {
    if (column.type.isNumber) {
      return faker.randomGenerator.decimal(scale: 1000000000);
    } else if (column.type.isSelect) {
      return (column.type.select!.items.toList()..shuffle()).first;
    } else if (column.type.isDate) {
      return DateTime.now()
          .add(Duration(days: faker.randomGenerator.integer(365, min: -365)))
          .toString();
    } else if (column.type.isTime) {
      final hour = faker.randomGenerator.integer(12).toString().padLeft(2, '0');
      final minute =
          faker.randomGenerator.integer(60).toString().padLeft(2, '0');
      return '$hour:$minute';
    } else {
      return "";
    }
  }

  static PlutoRow rowByColumns(List<PlutoColumn> columns) {
    final cells = <String, PlutoCell>{};

    for (var column in columns) {
      cells[column.field] = PlutoCell(
        value: valueByColumnType(column),
      );
    }

    return PlutoRow(cells: cells);
  }
  

  static List<PlutoRow> rowsByColumns({
    required int length,
    required List<PlutoColumn> columns,
  }) {
    return List<int>.generate(length, (index) => index).map((_) {
      return rowByColumns(columns);
    }).toList();
  }
}

class LocationGrid extends StatefulWidget {
  @override
  State<LocationGrid> createState() => _LocationGridState();
}

class _LocationGridState extends State<LocationGrid> {

  final List<PlutoColumn> columns = [];
  final List<PlutoRow> rows = [];
  static PlutoGridStateManager? stateManager = null;

  @override
  void initState() {
    super.initState();

    /// Columns must be provided at the beginning of a row synchronously.
    columns.addAll(DummyData(30, 0).columns);

    fetchRows().then((fetchedRows) {
      /// When there are many rows and the UI freezes when the grid is loaded
      /// Initialize the rows asynchronously through the initializeRowsAsync method
      /// Add rows to stateManager.refRows.
      /// And disable the loading screen.
      PlutoGridStateManager.initializeRowsAsync(
        columns,
        fetchedRows,
      ).then((value) {
        stateManager?.refRows.addAll(FilteredList(initialList: value));
        stateManager?.setShowLoading(false);
      });
    });
  }

  Future<List<PlutoRow>> fetchRows() {
    final Completer<List<PlutoRow>> completer = Completer();

    final List<PlutoRow> _rows = [];

    int count = 0;

    const max = 100;

    const chunkSize = 100;

    const totalRows = chunkSize * max;

    Timer.periodic(const Duration(milliseconds: 1), (timer) {
      if (count == max) {
        return;
      }

      ++count;

      Future(() {
        return DummyData.rowsByColumns(length: chunkSize, columns: columns);
      }).then((value) {
        _rows.addAll(value);

        if (_rows.length == totalRows) {
          completer.complete(_rows);

          timer.cancel();
        }
      });
    });

    return completer.future;
  }

  @override
  Widget build(BuildContext context) {
    return PlutoGrid(
        columns: columns,
        rows: rows,
        onChanged: (PlutoGridOnChangedEvent event) {
          print(event);
        },
        onLoaded: (PlutoGridOnLoadedEvent event) {
          stateManager = event.stateManager;

          /// When the grid is finished loading, enable loading.
          stateManager?.setShowLoading(true);
        },
        configuration: const PlutoGridConfiguration(),
    );
  }
}

with adding rows using your way, still not working. its not adding rows issue.

This issue is stale because it has been open for 30 days with no activity.

This issue was closed because it has been inactive for 14 days since being marked as stale.