Skip to content

Commit c615cdc

Browse files
Merge pull request #149 from 3212-Enertech-Global/main
feat: #112 Searchable Multiselect Dropdown
2 parents e4a02e5 + 52a64ba commit c615cdc

File tree

4 files changed

+662
-0
lines changed

4 files changed

+662
-0
lines changed

example/lib/main.dart

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,43 @@ class MyHomePageState extends State<MyHomePage> {
8989
country.toLowerCase().contains(filter.toLowerCase()),
9090
),
9191
const SizedBox(height: 15),
92+
FormBuilderSearchableMultiSelectDropdown<String>(
93+
name: 'multiselect_dropdown_offline',
94+
items: allCountries,
95+
onChanged: _onChanged,
96+
decoration: const InputDecoration(
97+
labelText: 'Multiselect Dropdown Offline',
98+
),
99+
popupProps: const PopupPropsMultiSelection.menu(
100+
showSearchBox: true,
101+
fit: FlexFit.loose,
102+
),
103+
filterFn: (country, filter) =>
104+
country.toLowerCase().contains(filter.toLowerCase()),
105+
),
106+
const SizedBox(height: 15),
107+
FormBuilderSearchableMultiSelectDropdown<String>(
108+
name: 'multiselect_dropdown_online',
109+
onChanged: _onChanged,
110+
asyncItems: (filter, _) async {
111+
await Future.delayed(const Duration(seconds: 1));
112+
return allCountries
113+
.where(
114+
(element) => element.toLowerCase().contains(
115+
filter.toLowerCase(),
116+
),
117+
)
118+
.toList();
119+
},
120+
decoration: const InputDecoration(
121+
labelText: 'Multiselect Dropdown Online',
122+
),
123+
popupProps: const PopupPropsMultiSelection.menu(
124+
showSearchBox: true,
125+
fit: FlexFit.loose,
126+
),
127+
),
128+
const SizedBox(height: 15),
92129
FormBuilderColorPickerField(
93130
name: 'color_picker',
94131
initialValue: Colors.yellow,

lib/form_builder_extra_fields.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export 'package:flutter_rating_bar/flutter_rating_bar.dart';
44
export 'src/fields/form_builder_color_picker.dart';
55
export 'src/fields/form_builder_rating_bar.dart';
66
export 'src/fields/form_builder_searchable_dropdown.dart';
7+
export 'src/fields/form_builder_searchable_multiselect_dropdown.dart';
78
export 'src/fields/form_builder_signature_pad.dart';
89
export 'src/fields/form_builder_touch_spin.dart';
910
export 'src/fields/form_builder_typeahead.dart';
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import 'package:dropdown_search/dropdown_search.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:flutter_form_builder/flutter_form_builder.dart';
4+
5+
/// Field for selecting value(s) from a searchable list
6+
class FormBuilderSearchableMultiSelectDropdown<T>
7+
extends FormBuilderFieldDecoration<List<T>> {
8+
///offline items list
9+
final List<T> items;
10+
11+
///selected items
12+
final List<T> selectedItems;
13+
14+
///to customize list of items UI
15+
final DropdownSearchBuilder<List<T>>? dropdownBuilder;
16+
17+
///customize the fields the be shown
18+
final DropdownSearchItemAsString<T>? itemAsString;
19+
20+
/// custom filter function
21+
final DropdownSearchFilterFn<T>? filterFn;
22+
23+
///function that compares two object with the same type to detected if it's the selected item or not
24+
final DropdownSearchCompareFn<T>? compareFn;
25+
26+
///dropdownSearch input decoration
27+
final InputDecoration? dropdownSearchDecoration;
28+
29+
/// How the text in the decoration should be aligned horizontally.
30+
final TextAlign? dropdownSearchTextAlign;
31+
32+
/// How the text should be aligned vertically.
33+
final TextAlignVertical? dropdownSearchTextAlignVertical;
34+
35+
/// An optional method to call with the final value when the form is saved via
36+
//final FormFieldSetter<List<T>>? onSavedMultiSelection;
37+
38+
/// callback executed before applying value change
39+
final BeforeChange<List<T>>? onBeforeChange;
40+
41+
///called when a new item added on Multi selection mode
42+
final OnItemAdded<T>? popupOnItemAdded;
43+
44+
///called when a new item added on Multi selection mode
45+
final OnItemRemoved<T>? popupOnItemRemoved;
46+
47+
///widget used to show checked items in multiSelection mode
48+
final DropdownSearchPopupItemBuilder<T>? popupSelectionWidget;
49+
50+
///widget used to validate items in multiSelection mode
51+
final ValidationMultiSelectionBuilder<T?>?
52+
popupValidationMultiSelectionWidget;
53+
54+
///widget to add custom widget like addAll/removeAll on popup multi selection mode
55+
final ValidationMultiSelectionBuilder<T>? popupCustomMultiSelectionWidget;
56+
57+
///function that returns item from API
58+
final DropdownSearchOnFind<T>? asyncItems;
59+
60+
//
61+
final PopupPropsMultiSelection<T> popupProps;
62+
63+
///custom dropdown clear button icon properties
64+
final ClearButtonProps? clearButtonProps;
65+
66+
/// style on which to base the label
67+
final TextStyle? dropdownSearchTextStyle;
68+
69+
///custom dropdown icon button properties
70+
final DropdownButtonProps? dropdownButtonProps;
71+
72+
// Creates field for selecting value(s) from a searchable list
73+
FormBuilderSearchableMultiSelectDropdown({
74+
super.key,
75+
super.autovalidateMode,
76+
super.enabled,
77+
super.focusNode,
78+
super.onSaved,
79+
super.validator,
80+
super.decoration,
81+
required super.name,
82+
super.initialValue,
83+
super.onChanged,
84+
super.valueTransformer,
85+
super.onReset,
86+
this.asyncItems,
87+
this.compareFn,
88+
this.dropdownSearchDecoration,
89+
this.dropdownSearchTextAlign,
90+
this.dropdownSearchTextAlignVertical,
91+
this.filterFn,
92+
this.itemAsString,
93+
this.items = const [],
94+
this.onBeforeChange,
95+
this.popupOnItemAdded,
96+
this.popupOnItemRemoved,
97+
this.popupSelectionWidget,
98+
this.selectedItems = const [],
99+
this.popupProps = const PopupPropsMultiSelection.menu(
100+
showSearchBox: true,
101+
fit: FlexFit.loose,
102+
),
103+
this.clearButtonProps,
104+
this.dropdownSearchTextStyle,
105+
this.dropdownButtonProps,
106+
this.dropdownBuilder,
107+
}) : assert(T == String || compareFn != null),
108+
popupCustomMultiSelectionWidget = null,
109+
popupValidationMultiSelectionWidget = null,
110+
super(
111+
builder: (field) {
112+
final state =
113+
field as FormBuilderSearchableMultiSelectDropdownState<T>;
114+
return DropdownSearch<T>.multiSelection(
115+
autoValidateMode: autovalidateMode,
116+
items: (filter, infiniteScrollProps) => asyncItems == null
117+
? items
118+
: asyncItems(filter, infiniteScrollProps),
119+
decoratorProps: DropDownDecoratorProps(
120+
decoration: state.decoration,
121+
textAlign: dropdownSearchTextAlign,
122+
textAlignVertical: dropdownSearchTextAlignVertical,
123+
baseStyle: dropdownSearchTextStyle,
124+
),
125+
suffixProps: DropdownSuffixProps(
126+
clearButtonProps: clearButtonProps ?? const ClearButtonProps(),
127+
dropdownButtonProps:
128+
dropdownButtonProps ?? const DropdownButtonProps(),
129+
),
130+
enabled: state.enabled,
131+
filterFn: filterFn,
132+
itemAsString: itemAsString,
133+
compareFn: compareFn,
134+
popupProps: popupProps,
135+
onBeforeChange: onBeforeChange,
136+
onChanged: (value) {
137+
state.didChange(value);
138+
},
139+
dropdownBuilder: dropdownBuilder,
140+
selectedItems: state.value ?? [],
141+
);
142+
},
143+
);
144+
145+
@override
146+
FormBuilderFieldDecorationState<
147+
FormBuilderSearchableMultiSelectDropdown<T>,
148+
List<T>
149+
>
150+
createState() => FormBuilderSearchableMultiSelectDropdownState<T>();
151+
}
152+
153+
class FormBuilderSearchableMultiSelectDropdownState<T>
154+
extends
155+
FormBuilderFieldDecorationState<
156+
FormBuilderSearchableMultiSelectDropdown<T>,
157+
List<T>
158+
> {}

0 commit comments

Comments
 (0)