Flutter Textformfield search receives data but does not display other data - flutter

This is my search code. It works by typing id the codes to display the information.
onSearch(String text) async {
if (text.isNotEmpty) {
List<Item> itemList = [];
for (var item in items) {
if (item.custnum == text.toLowerCase().toUpperCase()) {
itemList.add(item);
}
}
setState(() {
searchitems.clear();
searchitems.addAll(itemList);
print('name : ${searchitems[0].name}');
// if (searchitems.isEmpty) {
// searchitems = [];
// print('searchitems : ${searchitems[0].address!.length}');
// print('searchitems : ${searchitems[0].address!}');
});
} else {
setState(() {
searchCus.clear();
searchitems.clear();
// searchitems.addAll(items);
print('searchitems : $searchitems');
});
}
}
This is my textformfield, it can find and display data. But what I will do is Getting a code from another page It's received and shows the code. But it doesn't show me the information. It has to delete and type at least 1 new password to show the information. Please help me i tried a lot.
TextFormField(
initialValue:
'${searchCus.isEmpty ? "" : searchCus[widget.indexCus].custnum}',
onChanged: onSearch,
decoration: InputDecoration(
labelText: 'custnum',
labelStyle: TextStyle(fontFamily: 'supermarket', fontSize: 14),
isDense: true,
),
),

The reason the initial value not do the search is that you search logic is only works when you type in the textfield, if your initial value come from class constructor you can call onSearch in initState like this:
#override
void initState() {
super.initState();
if(searchCus.isNotEmpty){
onSearch(searchCus[widget.indexCus].custnum);
}
}

Related

Can't get back to initial list after adding search functionnality in flutter

i'm trying to fetch users through a search bar! the search function works perfectly but everytime I try to remove some letters it doesn't get me back to the intial full list of users.
Textfield for search:
TextField(
controller: searchController,
decoration: InputDecoration(
prefixIcon: const Icon(Icons.search),
hintText: 'Search for users',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: Colors.grey))),
onChanged: (value) => searchUser(value),
),
Search function:
void searchUser(String query) {
final suggstions = users?.where((user) {
final userName = user.name.toLowerCase();
final input = query.toLowerCase();
return userName.contains(input);
}).toList();
setState(() {
users = suggstions;
});
}
initState:
#override
void initState() {
super.initState();
getUsersFromDatabase();
}
I'd be grateful if anyone can help!
since you only fetch the list once in initState, then you have to separate in to different list.
List users = [];
List showUser =[];
in your getUsersFromDatabase()
users = your api response list;
showUser = users;
for the search function you have to filter the users and assign it to showUser
void searchUser(String query) {
if( String query == '') {
setState(() { // setState to update UI
showUser = users); // when empty string, show all users
});
return; // return it, so the code below will not executed
}
// filter the users, and the result assign to show users.
// so your list of user will only change once in initState
final suggstions = users?.where((user) {
final userName = user.name.toLowerCase();
final input = query.toLowerCase();
return userName.contains(input);
}).toList();
setState(() {
showUsers = suggstions;
});
}
last, display the showUser not the users
ListView(
children: showUser.map()
.....

Possible to update/rebuild open DropdownButtonFormField?

Is it possible to uppdate or rebuild open DropdownButtonFormField, e.g. with GetIt or Provider - or perhaps by using a stream - when new data becomes available?
At the moment the options in the dropdown gett added as data arrives while the dropdown is un-expanded, but once the user taps on it only those items that were available at the time they tapped are available and new items are only available if and when the user closes and reopens the dropdown.
My user interface currently has
DropdownButtonFormField(
value: dropdownValue,
icon: const Icon(Icons.keyboard_arrow_down),
items: dropdownItems,
validator: (value) =>
(value == null || value == "0") ? 'Please select a recipient.' : null,
onChanged: (String? newValue) {
if (newValue != null) {
dropdownValue = newValue;
} else {
dropdownValue = "0";
}
setState(() {});
},
)
the dropdownItems comes from
List<DropdownMenuItem<String>>? get dropdownItems {
if (clientListicle.items.isEmpty) {
developer.log('go fetch', name: '_MessagePageState get dropdownItems');
fetchClients();
}
for (var element in clientListicle.items) {
DropdownMenuItem<String> potentialItem =
DropdownMenuItem(value: element.id.toString(), child: Text(element.title));
bool isHave = false;
for (var exstElement in menuItems) {
if (exstElement.value == element.id.toString()) {
isHave = true;
}
}
if (!isHave) {
menuItems.add(potentialItem);
setState(() {});
}
}
if (menuItems.length == 1) {
return null;
} else {
return menuItems;
}
}
clientListicle is a singleton that inherits from a class that extends ChangeNotifier, and is registered in GetIt.
I've had a quick look at the implementation of DropdownButtonFormField and FormField that it extends, thinking maybe one could add functionality to or override a build method or some such, but think maybe I'm missing something simpler/easier and am probably just a bit out of my depth here... :-)
Update, I've tried adding a final _formFieldKey = GlobalKey<FormFieldState>(); key to the dropdown widget thinking I might be able to use that from the getter to trigger a rebuild, but no luck yet.

InitialValue isn't working properly in Multi-Select package Flutter

so I am using MultiSelectBottomSheetField in this package. I posted on their github as well as an issue but it seems fairly inactive so i came here looking for help.
And I am having some issues with the initialValue parameter for it. So at the moment, I have data saved in firestore as a string but its in the format of a list. And what i was trying to do was get the string data from firestore -> convert to a list with the respective class -> and then show as initial value in the above package/widget. But whats happening is that the initial value isnt showing, even though the value is not empty.
So for context this is how I change to list from firestore string:
List<Skill?> skillList = [];
void changeSkillToList(String? stringList) {
int indexOfOpenBracket = stringList!.indexOf("[");
int indexOfLastBracket = stringList.lastIndexOf("]");
var noBracketString =
stringList.substring(indexOfOpenBracket + 1, indexOfLastBracket);
var list = noBracketString.split(", ");
for (var i = 0; i < list.length; i++) {
skillList.add(Skill(id: 1, name: list[i].toString()));
}
}
this is how i use the acc widget:
final _skillItems =
skill.map((skill) => MultiSelectItem<Skill>(skill, skill.name)).toList();
MultiSelectBottomSheetField<Skill?>(
selectedColor: Color(0xFF5DB075),
selectedItemsTextStyle:
TextStyle(color: Colors.white),
initialChildSize: 0.4,
decoration: BoxDecoration(),
listType: MultiSelectListType.CHIP,
initialValue: skillList,
searchable: true,
items: _skillItems,
buttonText: Text("Select your skills...",
style: GoogleFonts.inter(
color: Color(0xFFBDBDBD),
fontSize: 16)),
onConfirm: (values) {
context
.read(pharmacistSignUpProvider.notifier)
.changeSkillList(values);
},
chipDisplay: MultiSelectChipDisplay(
items: context
.read(pharmacistSignUpProvider.notifier)
.skillList
?.map((e) =>
MultiSelectItem(e, e.toString()))
.toList(),
chipColor: Color(0xFF5DB075),
onTap: (value) {
context
.read(
pharmacistSignUpProvider.notifier)
.skillList
?.remove(value);
return context
.read(
pharmacistSignUpProvider.notifier)
.skillList;
},
textStyle: TextStyle(color: Colors.white),
),
),
And this is my initState:
List<Skill?> skillList = [];
#override
void initState() {
skillList = changeSkillToList(context
.read(pharmacistMainProvider.notifier)
.userDataMap?["knownSkills"]);
print(skillList);
super.initState();
}
If someone could help me out, it would be very appreciated. Let me know if you guys have any questions
Thanks!!
I get some problem and I fix it by adding the == operator to my entity in your case skill
#override
bool operator ==(Object other) {
return other is Skill && this.id == other.id;
}
inside your Skill class

Adding Search function to SliverList in Flutter

I'm trying to add a search function to my SliverList containing multiple list items.
Just before looping through my List of elements I added the TextField to implement the search function itself.
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
onChanged: (value) {
filterSearchResults(value);
},
controller: editingController,
decoration: InputDecoration(
labelText: "Search",
hintText: "Animal Name",
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(4.0))),
),
),
),
for (var animal in response)
Card( /* Elements to be searched later */)
as for the fluterSearchResults function:
void filterSearchResults(String query) {
List response = widget.res; // <- contains the animal data I'd like to search through
List<String> searchList = List<String>();
if (query.isNotEmpty) {
searchList.forEach((response) {
if (response.contains(query)) {
searchList.add(response);
}
setState(() {
items.clear();
items.addAll(searchList);
});
});
return;
} else {
setState(() {
items.clear();
items.addAll(searchList);
});
}
}
one element of the data within widget.res looks like this:
[{
id: 1,
game: "basegame",
name: "Aardvark",
continent: [
"Africa"
],
biome: [
"Grassland",
"Tropical"
],
can_swim: true,
status: "Least Concern",
exhibit: false,
dominance: "None",
relationship_human: "Shy",
mating_system: "Polygynous"
}]
the my function does not seem to add the elements properly to the searchList I'd like to display as long as the query is not empty but I'm unable to find the issue here.
Part of fluterSearchResults function is the reason causing error.
You use the same list for searching, [searchList].
It always search in an empty list.
Try
List responseList = widget.res;
List<String> searchList = List<String>();
responseList.forEach((response) {
if (response.contains(query)) {
searchList.add(response);
}
setState(() {
items.clear();
items.addAll(searchList);
});
});
return;
I hope the problem will be solved.

How to detect user has stopped typing in TextField?

I am using a TextField under which onChanged function
I am calling my code but the issue right now is the code gets execute everytime a new word is either entered or deleted.
what I am looking for is how to recognize when a user has stopped typing.
means adding some delay or something like that.
I have tried adding delay also using Future.delayed function but that function also gets executed n number of times.
TextField(
controller: textController,
onChanged: (val) {
if (textController.text.length > 3) {
Future.delayed(Duration(milliseconds: 450), () {
//code here
});
}
setState(() {});
},
)
Thanks to #pskink
I was able to achieve the functionality I was looking for.
import stream_transform package in your pubspec.yaml
stream_transform: ^0.0.19
import 'package:stream_transform/stream_transform.dart';
StreamController<String> streamController = StreamController();
#override
void initState() {
streamController.stream
.transform(debounce(Duration(milliseconds: 400)))
.listen((s) => _validateValues());
super.initState();
}
//function I am using to perform some logic
_validateValues() {
if (textController.text.length > 3) {
// code here
}else{
// some other code here
}
}
TextField code
TextField(
controller: textController,
onChanged: (val) {
streamController.add(val);
},
)
In my case I also required flutter async.
//pubspec.yaml
stream_transform: ^2.0.0
import 'dart:async';
import 'package:stream_transform/stream_transform.dart';
StreamController<String> streamController = StreamController();
// In init function
streamController.stream
.debounce(Duration(seconds: 1))
.listen((s) => {
// your code
});
// In build function
TextField(
style: TextStyle(fontSize: 16),
controller: messageController,
onChanged: (val) {
myMetaRef.child("isTyping").set(true);
streamController.add(val);
},
)
I find something so lighter in this link
it define this class
class Debouncer {
final int milliseconds;
Timer? _timer;
Debouncer({this.milliseconds=500});
run(VoidCallback action) {
if (null != _timer) {
_timer!.cancel();
}
_timer = Timer(Duration(milliseconds: milliseconds), action);
}
}
this sample will help you more
TextField(
decoration: new InputDecoration(hintText: 'Search'),
onChanged: (string) {
_debouncer.run(() {
print(string);
//perform search here
});
},
),