Why AutoCompleteTextField is not showing any suggestion in Flutter?

Issue

I am new to Flutter and currently working on a project where I need to show user a list of matched members so that a user can easily select one of them. For that I use AutoCompleteTextField. It is working fine as long as provided by already fetched list of members to it’s suggestion property. But I wonder, why it’s not working when I put it under BlocBuilder. Event hits on textChanged method and the state also returns a list but the suggestions are invisible.

  Widget autoCompleteSearchBar() {
    return BlocBuilder<OrderInfoBloc, MyOrderInfoStates>(
      builder: (context, state) {
          return AutoCompleteTextField<Member>(
            clearOnSubmit: false,
            style: TextStyle(
              color: Colors.black,
              fontSize: 16,
            ),
            decoration: InputDecoration(
              hintText: 'Search Member Here..',
              border: InputBorder.none,
              suffixIcon: IconButton(
                icon: Icon(Icons.cancel),
                iconSize: 20,
                color: Colors.yellow[700],
                onPressed: () {
                  _autoCompleteController.text = "";
                },
              ),
              contentPadding: EdgeInsets.fromLTRB(10, 30, 10, 20),
              hintStyle: TextStyle(color: Colors.grey),
            ),
            keyboardType: TextInputType.text,
            controller: _autoCompleteController,
            textChanged: (value) {
              context.read<OrderInfoBloc>().add(SearchTextChanged(text: value));
            },
            itemSubmitted: (item) async {
              _autoCompleteController.text = state.radioGroupValue == 'By Code'
                  ? item.memberNo
                  : item.memberName;
              context.read<OrderInfoBloc>().add(SelectedMember(member: item));
            },
            key: _key,
            suggestions: state.membersList,
            itemBuilder: (context, item) {
              print(item);
              // return state.radioGroupValue == 'By Code'
              //     ? autoCompleteSearchBarRow(
              //         item: item.memberNo, icon: Icon(Icons.person))
              //     : autoCompleteSearchBarRow(
              //         item: item.memberName, icon: Icon(Icons.person));
              return autoCompleteSearchBarRow(
                  item: item.memberNo, icon: Icon(Icons.person));
            },
            itemFilter: (item, query) {
              print(query);
              // bool _itemFilter;
              // if (_autoCompleteController.text.isNotEmpty) {
              //   _itemFilter = state.radioGroupValue == 'By Code'
              //       ? item.memberNo
              //           .toLowerCase()
              //           .startsWith(query.toLowerCase())
              //       : item.memberName
              //           .toLowerCase()
              //           .startsWith(query.toLowerCase());
              // } else {
              //   _autoCompleteController.text = '';
              //   _itemFilter = false;
              // }
              // return _itemFilter;
              return item.memberNo.toLowerCase().startsWith(query.toLowerCase());
            },
            itemSorter: (a, b) {
              // return state.radioGroupValue == 'By Code'
              //     ? a.memberNo.compareTo(b.memberNo.toLowerCase())
              //     : a.memberName.compareTo(b.memberName.toLowerCase());
              print(b);
              return a.memberNo.compareTo(b.memberNo.toLowerCase());
            },
          );
        }
    );
  }

  Widget autoCompleteSearchBarRow(
      {@required String item, @required Icon icon}) {
    return ListTile(
      leading: icon,
      title: Text(item),
    );
  }

Solution

Use the flutter_typeahead package which works well with flutter bloc

Now, come to the bloc side you don’t need to wrap your autocomplete widget with blocbuilder cause if you do so, the bloc will always repaint the widget whenever an event fires. so in your case when you are typing in the text box, event fires and bloc rebuild the widget and because of that suggestion don’t show up and even if you see suggestion they will be gone once the corresponding bloc state occurs and rebuild the widget

the recommended solution would be seen below

Don’t add any state to get suggestions just return the result or records from event as below. (below function added to Cubit file)

  Future<List<Item>> getProductItemsBySearchString(String item) async {
    return await itemRepository.getItemsByName(item);
  }

as you can see above I am returning item records directly from the getProductItemsBySearchString() event method (no bloc state)

Then use It like below

class ItemScreen extends StatelessWidget {
  // then you can call bloc event in function as below
  Future<List<Item>> getItemSuggestionsList(
      BuildContext context, String text) async {
    final bloc = context.read<ItemCubit>();

    List<Item> data = await bloc.getProductItemsBySearchString(text);

    if (data != null) {
      return data;
    } else {
      return null;
    }
  }

  @override
  Widget build(BuildContext context) {
    return TypeAheadField(
      getImmediateSuggestions: true,
      textFieldConfiguration: TextFieldConfiguration(
          controller: _itemEditingController,
          autofocus: false),
      suggestionsCallback: (pattern) {
        // call the function to get suggestions based on text entered
        return getItemSuggestionsList(context, pattern);
      },
      itemBuilder: (context, suggestion) {
        // show suggection list
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: ListTile(
            title: Text(suggestion.name),
            trailing: Text(
              'Item Code: ${suggestion.code}',
            ),
          ),
        );
      },
      onSuggestionSelected: (suggestion) {
       // get selected suggesion
      },
    );
  }
}

Answered By – Aakash kondhalkar

Answer Checked By – Marie Seifert (FlutterFixes Admin)

Leave a Reply

Your email address will not be published.