Open kfchengkf opened 3 years ago
Hello @kfchengkf ,
You can use searchFn
argument.
Here is an example with search_choices
plugin but it should work the same with searchable_dropdown
plugin:
SearchChoices.multiple(
items: items,
selectedItems: selectedItemsMultiCustomDisplayDialog,
onChanged: (value) {
setState(() {
selectedItemsMultiCustomDisplayDialog = value;
});
},
searchFn: (String keyword, items) {
print("Typed keyword: $keyword");
List<int> ret = [];
if (items != null && keyword.isNotEmpty) {
keyword.split(" ").forEach((k) {
int i = 0;
items.forEach((item) {
if (k.isNotEmpty &&
(item.value
.toString()
.toLowerCase()
.contains(k.toLowerCase()))) {
ret.add(i);
}
i++;
});
});
}
if (keyword.isEmpty) {
ret = Iterable<int>.generate(items.length).toList();
}
return (ret);
},
isExpanded: true,
)
Hi locus, Is it possible to customize either the done button or the close button to reference the typed search string, as mentioned previously, such that if the search string doesn't match, the button would be enabled and, when clicked, open a new widget with the search string in one field, and the user able to enter values for other fields ?
The UI must propose to the user the addition of an object to the list in case the keyword doesn’t match?
No. Only the field to be search should be added. The search field is the name of the object. If it doesn't exist, I can call the "Close" button that popup another screen with the name field preset. Other fields can then be edited on this screen too. I wonder if a "global" variable is needed to save the typed string in the searchFn, and then checked in the "Close" button function.
Hi @kfchengkf ,
I believe that the following code does what you are asking for. If not, I apologize for my misunderstanding.
List<DropdownMenuItem> editableItems = [];
final _formAddMissingKey = GlobalKey<FormState>();
final _fieldAddMissingKey = GlobalKey<FormFieldState>();
String inputString = "";
List<int> selectedItemsMultiAddMissingDialog = [];
List<DropdownMenuItem> editableItems = [];
bool multiAddMissingDialogPropose=false;
String multiAddMissingDialogProposeKeyword="";
...
addItemDialogWithProposal(String proposal) async {
return await showDialog(
context: MyApp.navKey.currentState?.overlay?.context ?? context,
builder: (BuildContext alertContext) {
return (AlertDialog(
title: Text("Add an item"),
content: Form(
key: _formAddMissingKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
key: _fieldAddMissingKey,
validator: (value) {
return ((value?.length ?? 0) < 6
? "must be at least 6 characters long"
: null);
},
initialValue: proposal,
onChanged: (value) {
inputString = value;
},
onSaved: (value){
inputString = value!;
},
autofocus: true,
),
TextButton(
onPressed: () {
if (_formAddMissingKey.currentState?.validate() ?? false) {
_fieldAddMissingKey.currentState?.save();
setState(() {
editableItems.add(DropdownMenuItem(
child: Text(inputString),
value: inputString,
));
});
Navigator.pop(alertContext, inputString);
}
},
child: Text("Ok"),
),
TextButton(
onPressed: () {
Navigator.pop(alertContext, null);
},
child: Text("Cancel"),
),
],
),
),
));
},
);
}
...
SearchChoices.multiple(
items: editableItems,
selectedItems: selectedItemsMultiAddMissingDialog,
onChanged: (value) {
setState(() {
selectedItemsMultiAddMissingDialog = value;
});
},
searchFn: (String keyword, items) {
List<int> ret = [];
if (items != null && keyword.isNotEmpty) {
keyword.split(" ").forEach((k) {
int i = 0;
items.forEach((item) {
if (k.isNotEmpty &&
(item.value
.toString()
.toLowerCase()
.contains(k.toLowerCase()))) {
ret.add(i);
}
i++;
});
});
}
if (keyword.isEmpty) {
ret = Iterable<int>.generate(items.length).toList();
}
multiAddMissingDialogPropose=ret.length==0;
multiAddMissingDialogProposeKeyword=keyword;
return (ret);
},
isExpanded: true,
disabledHint: (Function updateParent) {
return (TextButton(
onPressed: () {
addItemDialogWithProposal("").then((value) async {
if (value != null) {
selectedItemsMultiAddMissingDialog = [0];
updateParent(selectedItemsMultiAddMissingDialog);
}
});
},
child: Text("No choice, click to add one"),
));
},
closeButton: (List<int> values, BuildContext closeContext,
Function updateParent) {
return (editableItems.length >= 100||!multiAddMissingDialogPropose
? SizedBox.shrink()
: TextButton(
onPressed: () {
addItemDialogWithProposal(multiAddMissingDialogProposeKeyword).then((value) async {
if (value != null) {
int itemIndex = editableItems
.indexWhere((element) => element.value == value);
if (itemIndex != -1) {
selectedItemsMultiAddMissingDialog.add(itemIndex);
Navigator.pop(
MyApp.navKey.currentState?.overlay?.context ??
context);
updateParent(selectedItemsMultiAddMissingDialog);
}
}
});
},
child: Text("Add and select item"),
));
},
);
...
Note that I didn't try this with plugin searchable_dropdown
but with search_choices
. Maybe this works with both?
Hi Icuis,
Yes, exactly.
Thanks
You’re welcome @kfchengkf !
Hi,
I would like to know it it is possible to check if the current typed string matches anything. If no, then I would enable a button which can get the current typed search string, (so that I can further process it, e.g. create a new item based on the typed search string).
Thanks.