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.
https://pluto.weblaze.dev
MIT License
637 stars 291 forks source link

[Bug] TabView is Getting Null values on dynamic rebuild or from server or provider or global data #938

Closed jesussmile closed 9 months ago

jesussmile commented 9 months ago

I have been stuck on this for days, would appreciate if anyone could help, I have 3 tabs , one has a plutoGrid and the other two are just simple text widget, When i first open the tab the tab will generate data for plutogrid, I have then added a global variable in the code List<PlutoRow> monthlyGlobalCapRows = []; . Its purpose is to hold the generate list of rows so when i switch back and forth on tabs it will still give me the old data and avoid recalculating /building data for plutoRow

For the first time when i run the app it will run fine, when i go to another tab and back it will still show the old data , now for the second time when i switch to another tab and come back to the first one i get a null error

This is the code


List<PlutoRow> monthlyGlobalCapRows = [];

class MonthlySchedule extends StatefulWidget {
  const MonthlySchedule({Key? key}) : super(key: key);
  @override
  _MonthlyScheduleState createState() => _MonthlyScheduleState();
}

class _MonthlyScheduleState extends State<MonthlySchedule>
    with TickerProviderStateMixin {
  PlutoGridStateManager? _stateManager;
  List<PlutoColumn>? columns;
  String refreshData = 'captain';

  @override
  void initState() {
    super.initState();
    initialStateData();
    capData =
        Provider.of<RosterDataProvider>(context, listen: false).captainSnapShot;

    globalData = capData;
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: customFloatingActionButton(context),
      appBar: AppBar(
        title: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Text('Monthly Schedule '),
            Text(DateFormat('MMMM yyyy').format(_selectedDate)),
          ],
        ),
        bottomOpacity: 1,
        elevation: 0,
        automaticallyImplyLeading: false,
        actions: [
          monthsSelect(),
        ],
      ),
      body: DefaultTabController(
        length: 3,
        child: Column(
          children: [
            TabBar(
              physics: const NeverScrollableScrollPhysics(),
              onTap: onTap,
              indicator: tabC(),
              labelColor: Colors.white,
              indicatorColor: const Color.fromARGB(255, 102, 249, 4),
              indicatorSize: TabBarIndicatorSize.tab,
              unselectedLabelColor: Colors.black,
              tabs: const [
                Tab(text: 'Captain Schedule'),
                Tab(text: 'First Officer Schedule'),
                Tab(text: 'Cabin Crew Schedule'),
              ],
            ),
            Expanded(
              child: TabBarView(
                physics: const NeverScrollableScrollPhysics(),
                //controller: _tabController,
                children: [
                  buildGrid(capData, "captain", context),
                  Text('data'),
                  Text('data 2'),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  PlutoGrid buildGrid(
      List<Map<String, dynamic>> data, String type, BuildContext context) {
    print('buildGrid called');
    return PlutoGrid(
        mode: PlutoGridMode.selectWithOneTap,
        configuration: const PlutoGridConfiguration(),
        onSelected: (event) {},
        onLoaded: (PlutoGridOnLoadedEvent event) {
          // print('onLoaded called type $type');
          _stateManager = event.stateManager;
          _stateManager!.setShowLoading(true);
          _stateManager!.setSelectingMode(PlutoGridSelectingMode.cell);
          _stateManager!.setShowColumnFilter(true);
          _parseColumnRow(data, type, null, null);
        },
        columns: columns ?? [],
        rows: []
        // plutoRows ?? [],
        );
  }

  void _parseColumnRow(
    List<Map<String, dynamic>>? data,
    String type,
    DateTime? startDate,
    DateTime? endDate,
  ) async {
    if (columns != null) {
      _stateManager!.removeColumns(columns!);
    }
    if (startDate != null || endDate != null) {
      daysInMonth = DateTime(startDate!.year, startDate.month + 1, 0).day;
    } else {
      DateTime now = DateTime.now();
      daysInMonth = DateTime(now.year, now.month + 1, 0).day;
    }
    columnTitles = List.generate(
      daysInMonth,
      (index) => '${index + 1}',
    );
    columns?.clear();
    columns = [
      PlutoColumn(
        frozen: PlutoColumnFrozen.start,
        title: 'NAME',
        field: 'NAME',
        type: PlutoColumnType.text(),
        width: 195,
      ),
      PlutoColumn(
        title: 'TOTAL',
        field: 'TOTAL',
        type: PlutoColumnType.text(),
        width: 90,
      ),
    ];
    for (int i = 0; i < columnTitles.length; i++) {
      columns!.add(
        PlutoColumn(
          title: columnTitles[i],
          field: '${i + 1}',
          type: PlutoColumnType.text(),
          width: 54,
        ),
      );
    }
    if (type == 'captain') {
      List<PlutoRow> rows = [];
      if (monthlyGlobalCapRows.isEmpty) {
        captainRows = generateShift(data);
        monthlyGlobalCapRows = List.from(captainRows);
        rows = List.from(captainRows);
      } else {
        monthlyGlobalCapRows = List.from(captainRows);
        for (var i = 0; i < monthlyGlobalCapRows.length; i++) {
          final name = monthlyGlobalCapRows[i].cells['NAME']!.value;
          final total = monthlyGlobalCapRows[i].cells['TOTAL']!.value;
          print('provider $name $total');
        }
        rows = List.from(monthlyGlobalCapRows);
      }

      await PlutoGridStateManager.initializeRowsAsync(
        columns!,
        rows,
      ).then((value) {
        _stateManager!.removeAllRows();
        _stateManager!.insertColumns(0, columns!);
        _stateManager!.appendRows(rows);
        _stateManager!.notifyListeners();
      });
    }
    _stateManager!.setShowLoading(false);
  }

Now if you see the print statement ,

 for (var i = 0; i < monthlyGlobalCapRows.length; i++) {
          final name = monthlyGlobalCapRows[i].cells['NAME']!.value;
          final total = monthlyGlobalCapRows[i].cells['TOTAL']!.value;
          print('provider $name $total');
        }

It does print for the first time when i go to second tab and back, showing the logic is working properly but when i do it the second time i get the error

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value

the error is point on this line

          final name = monthlyGlobalCapRows[i].cells['NAME']!.value;

No clue , stuck , appreciate any help