androidfluttersearchcheckbox

How to add Search field for checkboxes, flutter


I want to add a search field for my checkboxes, Checkboxes are working great, just want to filter them according to search query. I have added a search bar as 'TextField' but not getting an expected output.

I tried a way, but when the query was empty, all checkboxes were selected automatically, and if we start searching, the checkbox that contains query gets selected.

Expected Output: All checkbox(es) that contain the search query gets showed on the screen.

calling from /main

void _showMultiSelect() async {
    final List<String> employees = [
      'Vaibhav Sutar',
      'Debayan',
      'Yash Singh',
      'Tahmeed Zamindar',
      'Vishhal Narkar',
    ];

    var results = await showDialog(
      context: context,
      builder: (BuildContext context) {
        return MultiSelect(employees: employees);
      },
    );

    if (results != null) {
      setState(() {
        _selectedEmployees = results;
      });
    }
  }

multi_select.dart

import "package:flutter/material.dart";
import "package:get/get.dart";
import "package:tact_tik/fonts/inter_light.dart";
import "package:tact_tik/fonts/inter_medium.dart";
import "package:tact_tik/utils/colors.dart";

class MultiSelect extends StatefulWidget {
  final List<String> employees;
  const MultiSelect({super.key, required this.employees});
  // void _runFilter(){}

  @override
  State<MultiSelect> createState() => _MultiSelectState();
}

List<String> selectedEmployees = [];
final List<String> employees = [
  'Vaibhav Sutar',
  'Debayan',
  'Yash Singh',
  'Tahmeed Zamindar',
  'Vishhal Narkar',
];

class _MultiSelectState extends State<MultiSelect> {
  void _itemChange(String employeeValue, bool isSelected) {
    setState(() {
      if (isSelected) {
        selectedEmployees.add(employeeValue);
      } else {
        selectedEmployees.remove(employeeValue);
      }
    });
  }

  List<String> _foundUsers = [];
  @override
  void initState() {
    _foundUsers = employees;
    super.initState();
  }

  _runFilter(String enteredKey) {
    List<String> results = [];
    if (enteredKey.isEmpty) {
      results = employees;
    } else {
      results = employees
          .where((employee) =>
              employee.toLowerCase().contains(enteredKey.toLowerCase()))
          .toList();
    }
    setState(() {
      _foundUsers = results;
    });
  }

  void _cancel() {
    Navigator.pop(context);
  }

  void _submit() {
    Navigator.pop(context, selectedEmployees);
    print(selectedEmployees);
  }

  @override
  Widget build(BuildContext context) {
    final bool isDark = Theme.of(context).brightness == Brightness.dark;

    return AlertDialog(
      scrollable: true,
      title: InterMedium(
        text: "Select Employees",
        color: isDark ? DarkColor.Primarycolor : LightColor.Primarycolor,
      ),
      content: SingleChildScrollView(
        child: Column(
          children: [
            TextField(
              onChanged: (value) => _runFilter(value),
              decoration: InputDecoration(
                  labelText: 'Search Employee', suffixIcon: Icon(Icons.search)),
            ),
            ListBody(
              children: widget.employees
                  .map((item) => CheckboxListTile(
                        activeColor: isDark
                            ? DarkColor.Primarycolor
                            : LightColor.Primarycolor,
                        value: selectedEmployees.contains(item),
                        title: InterLight(
                          text: item,
                        ),
                        controlAffinity: ListTileControlAffinity.leading,
                        onChanged: (isChecked) => _itemChange(item, isChecked!),
                      ))
                  .toList(),
            ),
          ],
        ),
      ),
      actions: [
        TextButton(
          onPressed: _cancel,
          child: InterMedium(
            text: 'Cancel',
            color: isDark ? DarkColor.color2 : LightColor.color4,
          ),
        ),
        ElevatedButton(
          onPressed: _submit,
          child: InterMedium(
              text: 'Submit',
              color: isDark ? DarkColor.Primarycolor : LightColor.Primarycolor),
        )
      ],
    );
  }
}

Current Output Output of provided code


Solution

  • You have to build the list based on the _foundUsers member. Currently you have in the ListBody constructor:

    children: widget.employees.map
    

    Replace this with:

    children: _foundUsers.map
    

    In a StatefulWidget you typically refer to widget. members only if they are not changed during the life cycle of the widget. In your case when you call setState you expect a rebuild based on the changed state which is stored in _foundUsers.