Flutter How to add a list of checkboxes inside a data table?

Viewed 73

My question: How can I add checkboxes to my data table to select rows?

The checkboxes are located in the first column of the table. The name of that column has a checkbox as well that selects all rows.

The individual checkbox in the column name does work and I can select all contacts.

However, when I dynamically create checkboxes using my List<DataRow> buildContactListOfDataRows method, I notice that when I setState() using the onChanged property, the value of the checkboxes is always true. This means that I cannot select/deselect individual columns.

Visual representation:

enter image description here

As requested I have updated my question with a testable snipped of my code:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const ContactsSearchPage(),
    );
  }
}

class Contact {
  String firstName;
  String lastName;
  String emailAddress;
  bool selected;

  Contact({
    this.firstName = '',
    this.lastName = '',
    this.emailAddress = '',
    this.selected = false,
  });
}

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

  @override
  // ignore: library_private_types_in_public_api
  _ContactsSearchPageState createState() => _ContactsSearchPageState();
}

class _ContactsSearchPageState extends State<ContactsSearchPage> {
//List to hold selected contacts
  List<Contact> selectedContacts = [];
  bool allContactsSelected = false;

  //Initialize data table data
  List<DataRow> contactRows = [];
  List<Contact> rowsData = [];
  List<DataColumn> contactColumns = [];
  List<String> columnsData = [
    "",
    "First Name",
    "Last Name",
    "Email Address",
  ];

  @override
  Widget build(BuildContext context) {
    //Fill the list of Columns
    contactColumns =
        buildListOfDataColumns(columnsData, Colors.white, TextAlign.center);

    //Fill the list of Contacts from object
    if (rowsData.isEmpty) {
      for (int i = 0; i < 4; i++) {
        rowsData.add(Contact(
          firstName: "user$i",
          lastName: "test$i",
          emailAddress: "email@test$i",
        ));
      }

      contactRows =
          buildContactListOfDataRows(rowsData, Colors.white, TextAlign.center);
    }

    return Center(
      child: Column(
        children: [
          Text(
            "Selected Contacts: ${selectedContacts.length}",
            style: const TextStyle(color: Colors.black),
          ),
          SizedBox(
            width: double.infinity,
            child: SingleChildScrollView(
              scrollDirection: Axis.vertical,
              child: FittedBox(
                fit: BoxFit.scaleDown,
                child: DataTable(
                    // ignore: prefer_const_constructors
                    headingTextStyle: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                      fontSize: 16,
                    ),
                    // ignore: prefer_const_constructors
                    decoration: BoxDecoration(
                      color: Colors.blueGrey,
                    ),
                    border: TableBorder.all(
                      width: 1.5,
                      color: Colors.white,
                      borderRadius: const BorderRadius.all(Radius.circular(10)),
                    ),
                    columns: contactColumns,
                    rows: contactRows),
              ),
            ),
          ),
        ],
      ),
    );
  }

  List<DataRow> buildContactListOfDataRows(
      List<Contact> rowsData, Color textColor, TextAlign textAlign) {
    List<DataRow> dataRows = [];

    for (int i = 0; i < rowsData.length; i++) {
      String firstName = rowsData[i].firstName;
      String lastName = rowsData[i].lastName;
      String emailAddress = rowsData[i].emailAddress;

      DataRow row = DataRow(
        cells: [
          DataCell(Theme(
              data: ThemeData(unselectedWidgetColor: Colors.white),
              child: Checkbox(
                value: rowsData[i].selected,
                onChanged: (value) {
                  setState(() {
                    rowsData[i].selected = value == null
                        ? false
                        : value == false
                            ? false
                            : true;
                  });

                  if (value == true) {
                    selectedContacts.add(rowsData[i]);
                  } else {
                    selectedContacts.remove(rowsData[i]);
                  }
                },
                activeColor: Colors.orange,
                tristate: true,
              ))),
          DataCell(Text(
            firstName,
            style: TextStyle(color: textColor),
            textAlign: textAlign,
          )),
          DataCell(Text(
            lastName,
            style: TextStyle(color: textColor),
            textAlign: textAlign,
          )),
          DataCell(Text(
            emailAddress,
            style: TextStyle(color: textColor),
            textAlign: textAlign,
          )),
        ],
      );

      dataRows.add(row);
    }

    return dataRows;
  }

  List<DataColumn> buildListOfDataColumns(
      List<String> columnData, Color textColor, TextAlign textAlign) {
    List<DataColumn> dataColumns = [];

    for (int i = 0; i < columnData.length; i++) {
      String columnName = columnData[i];
      DataColumn column = const DataColumn(label: Text(""));

      if (columnName == "") {
        column = DataColumn(
            label: Theme(
                data: ThemeData(unselectedWidgetColor: Colors.white),
                child: Checkbox(
                  value: allContactsSelected,
                  onChanged: (value) {
                    setState(() {
                      allContactsSelected = value == null
                          ? false
                          : value == false
                              ? false
                              : true;

                      if (selectedContacts.isNotEmpty) {
                        selectedContacts.clear();
                      }

                      if (allContactsSelected) {
                        for (var element in rowsData) {
                          element.selected = true;
                          selectedContacts.add(element);
                        }
                      } else {
                        for (var element in rowsData) {
                          element.selected = false;
                        }
                        selectedContacts.clear();
                      }
                    });
                  },
                  activeColor: Colors.orange,
                  tristate: true,
                )));
      } else {
        column = DataColumn(
          label: Text(
            columnName,
            style: TextStyle(color: textColor),
            textAlign: textAlign,
          ),
        );
      }

      dataColumns.add(column);
    }

    return dataColumns;
  }
}
1 Answers

I'm not sure I understand your problem correctly, but if it was how to bind functionality to the Checkbox, this State of a StatefulWidget should serve as a minimal working example for you:

  bool rememberMe = false;

  void _onRememberMeChanged(bool newValue) => setState(() {
    rememberMe = newValue;

    if (rememberMe) {
      // TODO: Here goes your functionality that remembers the user.
    } else {
      // TODO: Forget the user
    }
  });

call check box in list

   Checkbox(
      value: rememberMe,
      onChanged: _onRememberMeChanged
    );
Related