简体   繁体   中英

how to properly implement click events on columns, fields and rows with PaginatedDataTable

I'm new to flutter and dart, so this is my first app (yay!!!)

in general I'm trying to create a table with two static rows of data. since I'm a beginner that what I've decided to start and play with :)

I use the PaginatedDataTable component for that, and I create a class that extends DataTableSource for the data source of the table.

the default rows per page is set to 10, so even when I have two rows of data it shows 2 rows and 8 empty rows, is that that the default behaviour ? probably not and I'm missing something :)

so when I click on an empty row I get an exception that onTap isn't being implemented on that row.

to make my question clearer this is my code:

this is my Widget function that returns the PaginatedDataTable component

Widget searchPageTable()  {
  int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage;
  final List<DataColumn> _columns = new List<DataColumn>();
  _columns.add(new DataColumn(label: Text("col1"),onSort: onSort));
  _columns.add(new DataColumn(label: Text("col2"),onSort: onSort));
  _columns.add(new DataColumn(label: Text("col3"),onSort: onSort));
  return new PaginatedDataTable(header: Text("header"),
      columns: _columns,
      rowsPerPage: _rowsPerPage,
    source: new MyDataSource(),
  );
}

so here in the columns I added the onSort() function (for now an empty function) but I know that I can catch when clicking on column titles and implement that properly. moving on..

my data source is implement with the following code;

class MyDataSource extends DataTableSource {

  cellTapped() {

  }

  @override
  DataRow getRow(int index) {
    if (index == 0) {
      final List<DataCell> row = new List<DataCell>();
      row.add(new DataCell(Text("col1txt"),onTap: cellTapped));
      row.add(new DataCell(Text("col2txt"),onTap: cellTapped));
      row.add(new DataCell(Text("col3txt"),onTap: cellTapped));
      return new DataRow(cells: row);
    } else if (index == 1) {
      final List<DataCell> row = new List<DataCell>();
      row.add(new DataCell(Text("col1txt2"),onTap: cellTapped));
      row.add(new DataCell(Text("col2txt2"),onTap: cellTapped));
      row.add(new DataCell(Text("col3txt2"),onTap: cellTapped));
      return new DataRow(cells: row);
    } else {
      return null;
    }
  }

  @override
  int get selectedRowCount {
    return 0;
  }

  @override
  bool get isRowCountApproximate {
    return false;
  }

  @override
  int get rowCount {
    return 2;
  }
}

so here for each row I create a DataRow and in it for each column a DataCell and I implement an onTap for each DataCell. but what if I wanna change the onTap for each row and not for specific columns, how an I do that ?

and whenever I click on an empty row, I get the following exception:

flutter: ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown while handling a gesture:
flutter: The method 'call' was called on null.
flutter: Receiver: null
flutter: Tried calling: call(true)
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
flutter: #1      DataTable.build.<anonymous closure> (package:flutter/src/material/data_table.dart:586:38)
flutter: #2      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
flutter: #3      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
flutter: #4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
flutter: #5      TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
flutter: #6      TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
flutter: #7      PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
flutter: #8      PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
flutter: #9      PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
flutter: #10     _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:180:19)
flutter: #11     _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:158:22)
flutter: #12     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:138:7)
flutter: #13     _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:101:7)
flutter: #14     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:85:7)
flutter: #15     _invoke1 (dart:ui/hooks.dart:168:13)
flutter: #16     _dispatchPointerDataPacket (dart:ui/hooks.dart:122:5)
flutter:
flutter: Handler: onTap
flutter: Recognizer:
flutter:   TapGestureRecognizer#a6733(debugOwner: GestureDetector, state: possible, won arena, finalPosition:
flutter:   Offset(209.0, 375.5), sent tap down)
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════

in general here I just want to ignore click events on empty row. how to implement that ?

any information regarding this issue would be appreciated.

thanks :)

You first question: "the default rows per page is set to 10, so even when I have two rows of data it shows 2 rows and 8 empty rows, is that that the default behaviour ? probably not and I'm missing something :)"

Yes, this is the expected behaviour because it will create the number of rows specified in rows per page property.

Your 2nd question: "whenever I click on an empty row, I get the following exception:..."

This is because in your getRow function it returns null when index > 1 so the exception is also expected. Practically, you don't want to hard-code your data source and set rows per page proportionally based on how many rows your data source has. For instance, if you know your data source will start with 100 rows, then you can either set each page having 10 or 20 rows. You should ideally avoid having empty rows in the page by dynamically building the page based on your data source update. But this exception is not going to crash your app and to some extent can be ignored if you want to simplify things.

Your final question about handling onTap of each row.

I am assuming you want to execute some actions to the selected row(s), for instance, you can enable/disable some buttons based on whether there is any row being selected. Note that there is an actions property (of type List<Widget> ) on the PaginatedDataTable and you can put some buttons or other widgets you want. The way I did this is via passing in a event handler (such as onRowSelected which is simply a function taking no argument and returning nothing) into MyDataSource constructor and call it on onSelectedChanged handler within getRow function where you return a DataRow . This is an example of what I did to give you a specific idea:

class OrderSource extends DataTableSource {
  int _selectedCount = 0;
  final List<Order> _orders;
  final Function onRowSelected;
  OrderSource(this._orders, this.onRowSelected);

  @override
  DataRow getRow(int index) {
    assert(index >= 0);
    if (index >= _orders.length) return null;
    final Order order = _orders[index];
    return DataRow.byIndex(
        index: index,
        selected: order.selected,
        onSelectChanged: (bool value) {
          if (order.selected != value) {
            _selectedCount += value ? 1 : -1;
            assert(_selectedCount >= 0);
            order.selected = value;
            notifyListeners();
            onRowSelected();
            //print('selected rows: $selectedRowCount');
          }
        },
        cells: <DataCell>[
          DataCell(Text('${order.orderID}')),
          DataCell(Text('${order.side}')),
          ...),
        ]);
  }
}

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM