searchfield
searchfield copied to clipboard
RangeError onSubmit when selected value is not part of the list
Describe the bug A RangeError is thrown when the currently selected value is not part of the results list and the field is submitted with the enter key.
The following RangeError was thrown while calling onSubmitted for TextInputAction.done:
RangeError (index): Invalid value: Not in inclusive range 0..3: 6
When the exception was thrown, this was the stack:
#0 List.[] (dart:core-patch/growable_array.dart:264:36)
#1 _SearchFieldState.build.<anonymous closure> (package:searchfield/src/searchfield.dart:806:57)
searchfield.dart:806
#2 EditableTextState._finalizeEditing (package:flutter/src/widgets/editable_text.dart:3079:18)
editable_text.dart:3079
#3 EditableTextState.performAction (package:flutter/src/widgets/editable_text.dart:2910:9)
editable_text.dart:2910
#4 TextInput._handleTextInputInvocation (package:flutter/src/services/text_input.dart:1870:39)
text_input.dart:1870
#5 TextInput._loudlyHandleTextInputInvocation (package:flutter/src/services/text_input.dart:1753:20)
text_input.dart:175
To Reproduce Steps to reproduce the behavior:
- Provide a list of suggestions & a valid initialValue.
- Type a value in the searchfield that returns suggestions which don't include the selected value.
- Press the enter key to submit the field.
- The RangeError is thrown.
[X] By clicking this checkbox, I confirm I am using the latest version of the package found on pub.dev/searchfield
Expected behavior onSubmit should be called without throwing an error so that this case can be handled.
Actual behavior A RangeError is thrown and onSubmit is not called.
Proposed solution Allow for the selected item to be deselected when the search text changes. This can be done with an optional flag. e.g. deselectOnTextChanged
Alternatively, there could be a value property that holds the currently selected value like in DropdownButtonFormField for example. In that case we could manipulate the value in whatever way one might need.
Additional context I'm on Flutter 3.13.9
Hi @Areion0, Thanks for filing the issue , I tried to reproduce the issue but I was unable to reproduce it. Can you provide a minimal code sample and provide me with the exact steps to reproduce the error?
I verified it on the latest version of the package v1.0.1
I am also facing this issue. Any workaround?
I click on the textfield and start typing, then i use the keyboard arrow keys to navigate the options , when i click enter, i get the below error:
RangeError (index): Index out of range: no indices are valid: 0
When the exception was thrown, this was the stack: dart-sdk/lib/internal/js_dev_runtime/private/ddc_runtime/errors.dart 297:3 throw dart-sdk/lib/_internal/js_dev_runtime/private/js_array.dart 600:7 _get] packages/searchfield/src/searchfield.dart 546:44 handleSelectKeyPress packages/flutter/src/widgets/actions.dart 597:39 invoke packages/flutter/src/widgets/actions.dart 338:16 [_invoke] packages/flutter/src/widgets/actions.dart 666:27 invokeActionIfEnabled packages/flutter/src/widgets/shortcuts.dart 874:81 handleKeypress packages/flutter/src/widgets/shortcuts.dart 1065:20 [_handleOnKeyEvent] packages/flutter/src/widgets/focus_manager.dart 2002:27 handleKeyMessage packages/flutter/src/services/hardware_keyboard.dart 1103:16 [_dispatchKeyMessage] packages/flutter/src/services/hardware_keyboard.dart 1175:75 handleRawKeyMessage
@hitashaRajesh Are you facing this error on the latest version 1.0.5 ? If so can you please share a minimal code sample to reproduce the issue?
Thanks
Hello @maheshmnj, I've used the country search example to make a code sample. I've added Albania as the initial value and recorded a short video of the behavior I described.
Package version: 1.0.5 Flutter: 3.22.2
country_search.dart
code sample
import '../country_model.dart';
import 'package:flutter/material.dart';
import 'package:searchfield/searchfield.dart';
class CountrySearch extends StatefulWidget {
CountrySearch({Key? key, required this.title}) : super(key: key);
final String title;
@override
_CountrySearchState createState() => _CountrySearchState();
}
class _CountrySearchState extends State<CountrySearch> {
@override
void dispose() {
_searchController.dispose();
focus.dispose();
super.dispose();
}
final _searchController = TextEditingController();
@override
void initState() {
super.initState();
countries = data.map((e) => Country.fromMap(e)).toList();
}
final _formKey = GlobalKey<FormState>();
final focus = FocusNode();
List<Country> countries = [];
Country _selectedCountry = Country.init();
bool containsCountry(String text) {
final Country? result = countries.firstWhere(
(Country country) => country.name.toLowerCase() == text.toLowerCase(),
orElse: () => Country.init());
if (result!.name.isEmpty) {
return false;
}
return true;
}
get initialValue {
final country = countries.firstWhere((country) => country.name.contains("Albania"));
return SearchFieldListItem(country.name, item: country);
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Form(
key: _formKey,
child: SearchField(
focusNode: focus,
initialValue: initialValue,
suggestions: countries
.map((country) =>
SearchFieldListItem(country.name, item: country))
.toList(),
suggestionState: Suggestion.hidden,
controller: _searchController,
hint: 'Search by country name',
maxSuggestionsInViewPort: 4,
itemHeight: 45,
textCapitalization: TextCapitalization.words,
validator: (x) {
if (x!.isEmpty || !containsCountry(x)) {
return 'Please Enter a valid Country';
}
return null;
},
inputType: TextInputType.text,
onSuggestionTap: (SearchFieldListItem<Country> x) {
setState(() {
_selectedCountry = x.item!;
});
_formKey.currentState!.validate();
focus.unfocus();
},
),
),
),
Expanded(
child: Center(
child: _selectedCountry.name.isEmpty
? Text('select Country')
: CountryDetail(
country: _selectedCountry,
))),
ElevatedButton(
onPressed: () {
_formKey.currentState!.validate();
},
child: Text('validate')),
SizedBox(
height: 100,
)
],
)));
}
}
class CountryDetail extends StatefulWidget {
final Country? country;
CountryDetail({Key? key, required this.country}) : super(key: key);
@override
_CountryDetailState createState() => _CountryDetailState();
}
class _CountryDetailState extends State<CountryDetail> {
Widget dataWidget(String key, int value) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width * 0.15),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('$key:'),
SizedBox(
width: 16,
),
Flexible(
child: Text(
'$value',
style: TextStyle(fontSize: 30),
),
)
],
),
);
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 24),
alignment: Alignment.center,
child: Text(
widget.country!.name,
style: TextStyle(fontSize: 40),
),
),
SizedBox(
height: 20,
),
dataWidget('Population:', widget.country!.population),
dataWidget('Density', widget.country!.density),
dataWidget('Land Area (in Km\'s)', widget.country!.landArea)
],
);
}
}
https://github.com/maheshmnj/searchfield/assets/23741094/602f1f41-41fc-46c0-bcc0-3fb347d23269
thanks for the code sample and the demo, The issue is when user executes a search no option is being selected, I believe the first option in non empty result should be selected by default
Fixed and released in v1.0.6