flutter_typeahead
flutter_typeahead copied to clipboard
Maybe a feature -- but how does someone force a new getSuggestions to fire even if same text?
Here is the use case: We have a TypeAheadField .. and we have basically a "radio button set" that controls additional filters to be applied to the getSuggestions. The problem is that I can't think of any easy way to "fire" off the getSuggestions callback (and hence fire off the DB call and render a new suggestions box) from an external trigger like the user changing the radio button to use a different filter.
Nothing clever is jumping out at me looking at the code .. but .. I'm not that clever anyway. :)
Of course we are doing a setState() on change of buttons and I see it calling build (high level) and building the TypeAheadWidget .. which is probably calling ... build? But since the internal state within the TypeAheadWidget hasn't changed .. it's just being efficient and not doing anything. :)
@KaYBlitZ or @AbdulRahmanAlHamali -- or anyone -- any cool ideas on this one??
@KaYBlitZ -- Hey, any thoughts on this? Our app is sort of in limbo without figuring this out .. Cheers!
Been quite busy. But can you give the TypeAhead a focus node and just setFocus on the node? If you have getImmediateSuggestions set to true then that should work.
On Thu, Mar 14, 2019, 7:12 AM S McDowall [email protected] wrote:
@KaYBlitZ https://github.com/KaYBlitZ -- Hey, any thoughts on this? Our app is sort of in limbo without figuring this out .. Cheers!
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AbdulRahmanAlHamali/flutter_typeahead/issues/71#issuecomment-472807067, or mute the thread https://github.com/notifications/unsubscribe-auth/AFPpTqsUYYRWX94auqQmrsGCLwEZpKx9ks5vWi6VgaJpZM4bsGJK .
Tried that -- but since the text hasn't changed it doesn't fire getSuggestions :( We are now thinking of adding a keyboard controller and hacking the text input to force a refire -- but seems hacky .. code like:
void _fiddleTheKeyboard() {
if (_oldPattern?.isEmpty ?? true) {
// set the kb to "something" and then clear it
_recipientsSearchController.text = ' '; // couple spaces
_recipientsSearchController.clear();
} else {
// clear the kb and set it to the old pattern
_recipientsSearchController.clear();
_recipientsSearchController.text = _oldPattern;
}
_oldPattern = null; // clear out old search pattern so we force a new query
}
Was hoping for a cleaner method ..
Did you set getImmediateSuggestions to true? That should trigger the suggestions when there's focus.
On Thu, Mar 14, 2019, 12:35 PM S McDowall [email protected] wrote:
Tried that -- but since the text hasn't changed it doesn't fire getSuggestions :( We are now thinking of adding a keyboard controller and hacking the text input to force a refire -- but seems hacky .. code like:
void _fiddleTheKeyboard() { if (_oldPattern?.isEmpty ?? true) { // set the kb to "something" and then clear it _recipientsSearchController.text = ' '; // couple spaces _recipientsSearchController.clear(); } else { // clear the kb and set it to the old pattern _recipientsSearchController.clear(); _recipientsSearchController.text = _oldPattern; } _oldPattern = null; // clear out old search pattern so we force a new query }
Was hoping for a cleaner method ..
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/AbdulRahmanAlHamali/flutter_typeahead/issues/71#issuecomment-472952435, or mute the thread https://github.com/notifications/unsubscribe-auth/AFPpTr50jQHZ8geUy8YZctU2_fSk6vh0ks5vWnpkgaJpZM4bsGJK .
Yes, that option has always been on -- but it doesn't fire because the old pattern and new are the same .. and I think that is correct behavior because a build() can happen often in Flutter and if the pattern hasn't changed you (in general) don't want to re do getSuggestions .. unless you want to FORCE a refresh() ..
BTW -- the keyboard controller hack works .. but it's a hack .. :)
Glad the hack works. But I just tried out the focus method and it works for me? Tried it in the example app. I click the button an it focuses on the text field and it automatically gets the suggestions for me. Like so:
class _FormExampleState extends State<FormExample> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _typeAheadController = TextEditingController();
final FocusNode _focusNode = FocusNode();
String _selectedCity;
@override
void dispose() {
_focusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Form(
key: this._formKey,
child: Padding(
padding: EdgeInsets.all(32.0),
child: Column(
children: <Widget>[
Text('What is your favorite city?'),
TypeAheadFormField(
getImmediateSuggestions: true,
textFieldConfiguration: TextFieldConfiguration(
focusNode: _focusNode,
decoration: InputDecoration(labelText: 'City'),
controller: this._typeAheadController,
),
suggestionsCallback: (pattern) {
return CitiesService.getSuggestions(pattern);
},
itemBuilder: (context, suggestion) {
return ListTile(
title: Text(suggestion),
);
},
transitionBuilder: (context, suggestionsBox, controller) {
return suggestionsBox;
},
onSuggestionSelected: (suggestion) {
this._typeAheadController.text = suggestion;
},
validator: (value) {
if (value.isEmpty) {
return 'Please select a city';
}
},
onSaved: (value) => this._selectedCity = value,
),
SizedBox(
height: 10.0,
),
RaisedButton(
child: Text('Press me!'),
onPressed: () {
FocusScope.of(context).requestFocus(_focusNode);
},
)
],
),
),
);
}
}
Are you manually checking the old pattern vs the new pattern in your code and somehow cancelling getSuggestions if it's the same? This is already automatic in TypeAhead, specifically this code:
this._controllerListener = () {
// If we came here because of a change in selected text, not because of
// actual change in text
if (widget.controller.text == this._lastTextValue) return;
this._lastTextValue = widget.controller.text;
Not our use case -
Start with TypeAheadField having focus - type stuff
Have a button - on button press we want TypeAheadField to regain focus and call getSuggestions again because we have a new filter to apply inside the getSuggestions - but it’s the same input search pattern
On Mar 14, 2019, at 6:05 PM, Kenneth Liang [email protected] wrote:
Glad the hack works. But I just tried out the focus method and it works for me? Tried it in the example app. I click the button an it focuses on the text field and it automatically gets the suggestions for me. Like so:
class _FormExampleState extends State<FormExample> { final GlobalKey<FormState> _formKey = GlobalKey<FormState>(); final TextEditingController _typeAheadController = TextEditingController(); final FocusNode _focusNode = FocusNode();
String _selectedCity;
@override void dispose() { _focusNode.dispose(); super.dispose(); }
@override Widget build(BuildContext context) { return Form( key: this._formKey, child: Padding( padding: EdgeInsets.all(32.0), child: Column( children: <Widget>[ Text('What is your favorite city?'), TypeAheadFormField( getImmediateSuggestions: true, textFieldConfiguration: TextFieldConfiguration( focusNode: _focusNode, decoration: InputDecoration(labelText: 'City'), controller: this._typeAheadController, ), suggestionsCallback: (pattern) { return CitiesService.getSuggestions(pattern); }, itemBuilder: (context, suggestion) { return ListTile( title: Text(suggestion), ); }, transitionBuilder: (context, suggestionsBox, controller) { return suggestionsBox; }, onSuggestionSelected: (suggestion) { this._typeAheadController.text = suggestion; }, validator: (value) { if (value.isEmpty) { return 'Please select a city'; } }, onSaved: (value) => this._selectedCity = value, ), SizedBox( height: 10.0, ), RaisedButton( child: Text('Press me!'), onPressed: () { FocusScope.of(context).requestFocus(_focusNode); }, ) ], ), ), ); } } Are you manually checking the old pattern vs the new pattern in your code and somehow cancelling getSuggestions if it's the same? This is already automatic in TypeAhead, specifically this code:
this._controllerListener = () { // If we came here because of a change in selected text, not because of // actual change in text if (widget.controller.text == this._lastTextValue) return;
this._lastTextValue = widget.controller.text;
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.
BTW -- I think there is a very similar request in the PageWise widget too if I am reading that correctly ..
is there away to just find only the item or text that is typed in the box. exmaple I use it for codes, if someone type 100, i dont need 1001 or 1002 coming up.
Have any other solution @sjmcdowall ?
FWIW, I have this need as well.
I got this to work using the built in Autocomplete<T> widget:
TextEditingController? autoCompleteEditingController;
String? selected;
return Autocomplete<SmartyModel>(
fieldViewBuilder:
(context, textEditingController, focusNode, onFieldSubmitted) {
autoCompleteEditingController = textEditingController;
return TextFormField(
controller: textEditingController,
focusNode: focusNode,
);
},
optionsBuilder: (TextEditingValue textEditingValue) async {
if (textEditingValue.text == '') {
return const Iterable.empty();
} else {
return await provider.search(
textEditingValue.text,
selected,
);
}
},
displayStringForOption: (option) => option.toString(),
onSelected: (option) {
if (selected != null) {
selected = null;
autoCompleteEditingController!.text = option.toString();
} else {
selected = option.toSelectedString();
autoCompleteEditingController!.text = option.toSearchString();
}
},
);
In 2023, I also have this need, but I haven't found a solution.
import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart'; // ^5.2.0
void main() {
runApp(
MaterialApp(
home: const HomeWidget(),
theme: ThemeData.dark(),
),
);
}
class HomeWidget extends StatelessWidget {
const HomeWidget({super.key});
// A history of searches, for testing
@override
Widget build(BuildContext context) {
final List<String> history = <String>[
'Nairobi',
'New York',
'Prague',
'Berlin',
'Pretoria',
];
final SuggestionsController<String> suggestionsController =
SuggestionsController<String>();
final TextEditingController typeAheadController = TextEditingController();
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: TypeAheadField<String>(
suggestionsController: suggestionsController,
controller: typeAheadController,
hideKeyboardOnDrag: true,
hideWithKeyboard: false,
itemSeparatorBuilder: (BuildContext context, int index) => Divider(
color: Colors.grey.withOpacity(0.5),
),
itemBuilder: (BuildContext context, String value) => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
value,
),
IconButton(
onPressed: () {
history.remove(value); // Here it updates the list
// this refresh will help build the list again
suggestionsController.refresh();
},
icon: const Icon(
Icons.close,
color: Colors.red,
),
),
],
),
suggestionsCallback: (String search) =>history,
onSelected: (String value) {},
),
),
),
);
}
}
this code fires the research again,