I am building a desktop app using Flutter UI and the fluent_ui package. I am adding an AutoSuggestBox to one of my forms to suggest addresses as the user types. The addresses are fetched from a server. This is a contrived example of what I am doing:
AutoSuggestBox<AutoSuggestable>(
items: _items,
placeholder: widget.placeholder,
controller: _controller,
focusNode: _focusNode
)
and this is code that is triggered when the user types:
void _onTextChanged() async {
if (_debounce?.isActive ?? false) _debounce?.cancel();
_debounce = Timer(const Duration(milliseconds: 2000), () async {
loadItems();
});
}
void loadItems() async {
List<AutoSuggestable> results = await fetchThingsFromServer();
setState(() {
_items = results
.map((item) => AutoSuggestBoxItem<AutoSuggestable>(
value: item,
label: item.label,
)).toList();
});
}
If I set a break point in my build
method, when the user types in the box i can see that the build is called, and that _items
contains the right elements, but the AutoSuggestBox dropdown still shows "No result found".
Every once in a while -- in an apparently random fashion -- while i am typing the suggestions will pop up.
My current hypothesis is that updating the items passed to AutoSuggestBox is not enough to trigger it's dropdown to refresh, and I need to call something else? Unsure.
There are two problems with the approach I was taking here.
The first problem is due to the AutoSuggestBox filtering functionality. By default, AutoSuggestBox expects a list of items to search through, and filters by comparing the text inputted with the label of the items.
In this case, I am searching items against a server which does the filtering and returns the proper items. Additionally, the label of the items returned by the server doesn't match the text inputted. This means the auto filtering functionality of the AutoSuggestBox will filter out the items returned from the server and end up display nothing.
To solve this we can override the sorter
AutoSuggestBox property to not do any filtering:
sorter: (text, items) => items,
Fixing this will finally show the items returned from the server, but one keystroke too late. In fact if the user types in "cat" and waits an appropriate amount of time for the debounce function to trigger a server reload, no result is shown. It is only when the user types again that the AutoSuggestBox decides to re-render the dropdown items and show the result of "cat". By now the user has typed out "cater" tho, and we are still showing the results for "cat" :/
The issue here is that the AutoSuggestBox itemBuilder
property which rebuilds the items in the dropdown is not triggered when the items
property changes. It is triggered when the text in the box changes. This happens before the server has returned the new items, and so the result is not shown until the text changes again and the old results get drawn on screen.
In my opinion this is a flaw of the AutoSuggestBox fluent_ui
implementation, which doesn't seem to be made for a server side items rendering use-case. This in my mind is a very common use-case tho, and therefore i'd classify this as a bug. Either way my current workaround is to call this after the server returns the items:
WidgetsBinding.instance.addPostFrameCallback((_) {
(_autoSuggestKey.currentState as AutoSuggestBoxState).dismissOverlay();
(_autoSuggestKey.currentState as AutoSuggestBoxState).showOverlay();
});
This forces the overlay to be re drawn and the items to be shown. Not very elegant, but it gets the job done. I am planning to submit a feature request for the fluent_ui repo (or potentially submit a PR).