Flutter TypeAhead 小部件验证不起作用
Flutter TypeAhead widget validation is not working
我有一个表单,其中包含三种类型的小部件,例如 DropDown
、TextField
和 TypeAhead
。我已经导入了一个名为 flutter_typeahead
的包,它基本上是一个与 TextField 混合的动态 DropDown。(有关 flutter_typeahead
的更多信息:flutter_typeahead,但不需要知道 flutter_typeahead
小部件以便能够理解和解决问题。)
但是,当我尝试验证时,如果 TypeAhead
小部件为空或 null,那么我会向用户抛出错误。到目前为止一切正常。但是,当我填写表单的其他实例(DropDown
和 TextFields
)并让 TypeAhead
为空时,验证将不起作用。我的意思是,如果我填写 DropDowns 和 TextFields 并让 TypeAhead
为空,然后尝试提交表单实际提交它。但是,如果我让 TextField
为空或 DropDown
作为默认值,验证工作正常。
综上所述,当所有表单小部件为空时,TypeAhead
验证有效,只有 TypeAhead
为空时无效。
表单小部件
Form formWidget(Map<String, dynamic> map) {
return Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
children: [
customTypeAhead(map['stajTuru'], _stajTuruController,
_selectedStajTuru, 'Staj Türü'), //Custom typeahead widget
customTypeAhead(
map['doktor'], _doktorController, _selectedDoktor, 'Doktor'), //Custom typeahead widget
customDropDown(
_valueOrtam, map['ortam'], hintTextOrtam, onChangedOrtam),
customDropDown(
_valueKapsam, map['kapsam'], hintTextKapsam, onChangedKapsam),
customDropDown(_valueEtkilesim, map['etkilesim'], hintTextEtkilesim,
onChangedEtkilesim),
customDropDown(_valueCinsiyet, map['cinsiyet'], hintTextCinsiyet,
onChangedCinsiyet),
const SizedBox(
height: 20,
),
customTextField(
1, "Kayıt No ", 10, _formData.setKayitNo, isEmpty, _kayit, 80),
customTextField(
1, "Hastanın Yaşı", 3, _formData.setYas, isNumeric, _yas, 80),
customTextField(
1, "Şikayet", 10, _formData.setSikayet, isEmpty, _sikayet, 80),
customTextField(1, "Ayırıcı Tanı", 10, _formData.setAyiriciTani,
isEmpty, _ayirici, 80),
customTextField(5, "Kesin Tanı", 50, _formData.setKesinTani, isEmpty,
_kesin, 130),
customTextField(5, "Tedavi Yöntemi", 200, _formData.setTedaviYontemi,
isEmpty, _tedavi, 130),
],
),
);
}
customTypeAhead
Widget customTypeAhead(List<String> listItems, TextEditingController controller,
String? stajTuru,String labelText) {
//check if the typed item is in the list
List<String> getSuggestions(String query) {
return List.of(listItems).where((item) {
final queryLower = query.toLowerCase();
final itemLower = item.toLowerCase();
return itemLower.contains(queryLower);
}).toList();
}
return Padding(
padding: const EdgeInsets.all(PADDING_VALUE),
child: Column(
children: [
Text(
labelText,
style: TEXT_STYLE,
),
TypeAheadFormField<String?>(
onSuggestionSelected: (String? val) =>controller.text = val!,
itemBuilder: (context, String? suggestion) {
return ListTile(
title: Text(suggestion!),
);
},
suggestionsCallback: getSuggestions,
validator: (value) { // This is my validation method
bool isInTheList=false;
for(var item in listItems){
if(item==value) {
isInTheList=true;
}
}
if (value == null || value.isEmpty || isInTheList==false) {
return 'Lütfen ${labelText.toLowerCase()} seçiniz';
} else {
print("null returned");
return null;
}
},
textFieldConfiguration: TextFieldConfiguration(
controller: controller,
decoration: const InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: TEXT_COLOR,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: TEXT_COLOR,
)))),
),
],
),
);
}
提交函数
void formIlet() async {
if (formArguments != null) {
if (_formKey.currentState!.validate()) {
setFormArgumentState();
bool res = await _mySqlHelper.insertData(formArguments!.formData);
if (res) {
_helper.update(formArguments!.formData);
customSnackBar(context, 'Başarıyla gönderildi');
} else {
errorAlert(context);
}
}
} else {
if (_formKey.currentState!.validate()) {
setFormDataState();
isLoading = true;
bool res = await _mySqlHelper.insertData(_formData).then((val) {
setState(() {
isLoading = false;
_formKey.currentState?.dispose();
});
return val;
});
if (res) {
customSnackBar(context, 'Başarıyla gönderildi');
} else {
errorAlert(context);
}
}
}
}
我已经解决了这个问题。我不知道为什么会这样,但是在 Form 中使用 ListView 并不是一个好主意。这就是问题所在。所以,我用 Column 改变了 ListView 并用 SingleChildScrollView 包裹它,问题就解决了。
我有一个表单,其中包含三种类型的小部件,例如 DropDown
、TextField
和 TypeAhead
。我已经导入了一个名为 flutter_typeahead
的包,它基本上是一个与 TextField 混合的动态 DropDown。(有关 flutter_typeahead
的更多信息:flutter_typeahead,但不需要知道 flutter_typeahead
小部件以便能够理解和解决问题。)
但是,当我尝试验证时,如果 TypeAhead
小部件为空或 null,那么我会向用户抛出错误。到目前为止一切正常。但是,当我填写表单的其他实例(DropDown
和 TextFields
)并让 TypeAhead
为空时,验证将不起作用。我的意思是,如果我填写 DropDowns 和 TextFields 并让 TypeAhead
为空,然后尝试提交表单实际提交它。但是,如果我让 TextField
为空或 DropDown
作为默认值,验证工作正常。
综上所述,当所有表单小部件为空时,TypeAhead
验证有效,只有 TypeAhead
为空时无效。
表单小部件
Form formWidget(Map<String, dynamic> map) {
return Form(
key: _formKey,
child: ListView(
shrinkWrap: true,
children: [
customTypeAhead(map['stajTuru'], _stajTuruController,
_selectedStajTuru, 'Staj Türü'), //Custom typeahead widget
customTypeAhead(
map['doktor'], _doktorController, _selectedDoktor, 'Doktor'), //Custom typeahead widget
customDropDown(
_valueOrtam, map['ortam'], hintTextOrtam, onChangedOrtam),
customDropDown(
_valueKapsam, map['kapsam'], hintTextKapsam, onChangedKapsam),
customDropDown(_valueEtkilesim, map['etkilesim'], hintTextEtkilesim,
onChangedEtkilesim),
customDropDown(_valueCinsiyet, map['cinsiyet'], hintTextCinsiyet,
onChangedCinsiyet),
const SizedBox(
height: 20,
),
customTextField(
1, "Kayıt No ", 10, _formData.setKayitNo, isEmpty, _kayit, 80),
customTextField(
1, "Hastanın Yaşı", 3, _formData.setYas, isNumeric, _yas, 80),
customTextField(
1, "Şikayet", 10, _formData.setSikayet, isEmpty, _sikayet, 80),
customTextField(1, "Ayırıcı Tanı", 10, _formData.setAyiriciTani,
isEmpty, _ayirici, 80),
customTextField(5, "Kesin Tanı", 50, _formData.setKesinTani, isEmpty,
_kesin, 130),
customTextField(5, "Tedavi Yöntemi", 200, _formData.setTedaviYontemi,
isEmpty, _tedavi, 130),
],
),
);
}
customTypeAhead
Widget customTypeAhead(List<String> listItems, TextEditingController controller,
String? stajTuru,String labelText) {
//check if the typed item is in the list
List<String> getSuggestions(String query) {
return List.of(listItems).where((item) {
final queryLower = query.toLowerCase();
final itemLower = item.toLowerCase();
return itemLower.contains(queryLower);
}).toList();
}
return Padding(
padding: const EdgeInsets.all(PADDING_VALUE),
child: Column(
children: [
Text(
labelText,
style: TEXT_STYLE,
),
TypeAheadFormField<String?>(
onSuggestionSelected: (String? val) =>controller.text = val!,
itemBuilder: (context, String? suggestion) {
return ListTile(
title: Text(suggestion!),
);
},
suggestionsCallback: getSuggestions,
validator: (value) { // This is my validation method
bool isInTheList=false;
for(var item in listItems){
if(item==value) {
isInTheList=true;
}
}
if (value == null || value.isEmpty || isInTheList==false) {
return 'Lütfen ${labelText.toLowerCase()} seçiniz';
} else {
print("null returned");
return null;
}
},
textFieldConfiguration: TextFieldConfiguration(
controller: controller,
decoration: const InputDecoration(
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: TEXT_COLOR,
),
),
border: OutlineInputBorder(
borderSide: BorderSide(
color: TEXT_COLOR,
)))),
),
],
),
);
}
提交函数
void formIlet() async {
if (formArguments != null) {
if (_formKey.currentState!.validate()) {
setFormArgumentState();
bool res = await _mySqlHelper.insertData(formArguments!.formData);
if (res) {
_helper.update(formArguments!.formData);
customSnackBar(context, 'Başarıyla gönderildi');
} else {
errorAlert(context);
}
}
} else {
if (_formKey.currentState!.validate()) {
setFormDataState();
isLoading = true;
bool res = await _mySqlHelper.insertData(_formData).then((val) {
setState(() {
isLoading = false;
_formKey.currentState?.dispose();
});
return val;
});
if (res) {
customSnackBar(context, 'Başarıyla gönderildi');
} else {
errorAlert(context);
}
}
}
}
我已经解决了这个问题。我不知道为什么会这样,但是在 Form 中使用 ListView 并不是一个好主意。这就是问题所在。所以,我用 Column 改变了 ListView 并用 SingleChildScrollView 包裹它,问题就解决了。