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),
)
],
);
}
}
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
.