Multi-Select Dialogue in Flutter
Imagine a person, Mr. X, hired as a newbie flutter developer in the Research & Development department of an ordinary biscuit manufacturing agency. Eventually, the sales trend started to drop off on weekly basis.
To resolve this issue, the Head of Department held a meeting and decided to create a questionnaire in their existing app. The Project Manager distributed various tasks to the development team and assigned Mr. X with only a short time to write code along with the restriction to use any third-party libraries such as Pubspec Packages¹.
The job was to create a button that would pop a simple dialogue box allowing a user to select multiple options and hit submit.
So how would Mr. X solve this challenge!
Flutter has made programming not only easy but also interesting. Tons of hardcoded strings can be easily mapped using a few lines of dart code, one can overcome the defects of manual event handling. Using the declarative UI approach, flutter helps to write code efficiently within a few minutes.
After some brainstorming, Mr. X sketched a basic design that would full fill the required functionality in a decent manner.
Figure 1 illustrates such a sketch.
Upon observing the sketch, he concluded that the following widgets would be used throughout the scenario as shown in Figure 2.
- A custom Demo Page as the main page.
- An Elevated Button² to pop up the dialogue.
- A Simple Dialog³ that shows a question and list of options.
- A list of CheckboxListTile⁴ that wraps the option text in the title property & option selected in the value property.
- An Elevated Button wrapped in an Align⁵ widget for submission.
READY, STEADY CODE!
Mr. X used the concept of “Divide & Conquer” and started off by creating pages and widgets folder inside the lib folder.
Inside the widgets folder, he created a custom dialog as a Stateless Widget.
- To handle extensive text formatting, Mr. X declared the question as a widget instead of a simple string.
- To display the options, he created a variable answers that would hold the hardcoded text as a list of strings.
- To track the selected answers, he transformed the list into a Map<String, bool> mappedItem by creating a function called initMap that would return a map using dart’s Map.fromIterable⁶ constructor.
- Inside the build method, he created a SimpleDialog having question as its title and a list of CheckboxListTile that were wrapped inside a StatefulBuilder using the mappedItem keys.
- To check or uncheck the box, setState was used in the OnChanged callback function.
- Upon pressing the ElevatedButton, only items having true value would be returned by the dialog.
Inside the pages folder, Mr. X created a demo page that would simply show an ElevatedButton. On tapping this button, the MultiSelectDialog would pop upon the screen. After submission, the selected flavours would be stored inside a List flavors. To execute the code, he invoked the demopage in the main.dart file.
The final results can be illustrated below in figure 4 and 5.
IS IT OVER? NOT YET!
Although the basic functionality was completed but Mr. X noticed some enhancements that could resolve the following issues:
- A user can close the dialogue without making a selection at any instance.
- A validator is required to show error if the user makes no selection.
- The Flavours button should be replaced with a Form widget.
- Currently there’s no way to show number of flavours selected by the user.
To tackle these problems, Mr. X wrapped the MultiSelect Dialog inside a custom form field in the widgets folder.
- To create a custom form field, Mr. X extended the FormField⁷ class which is default provided by flutter.
- The base constructor is invoked using the super keyword to get the form field’s properties and call back functions.
- The onSaved & validator are the two stepping stones that would trigger based upon the form’s current state.
- The ElevatedButton was replaced with a custom elevated Card Container to make the button look larger and appealing.
- Multiple conditions were defined depending upon the form field’s state value like:
★ How to avoid null state?
★ How many flavors were selected by the user?
★ How to change the buttonText as per flavors selected?
- Instead of directly taking up the question and answers, now these would be forwarded to the MultipleSelectDialog through the MultiSelectFormField’s constructor.
- In case of validation failure, error handling became smooth using the form field’s state.hasError property.
- To integrate the changes with the demo page, Mr. X modified the basic code by replacing the ElevatedButton with a Form.
- A GlobalKey ⁸<FormState> was used to keep track of the form’s state.
- In the validator callback function, it was checked that at least one flavor should be selected by the user.
- The onSaved method would trigger only if the field is valid.
After executing the main.dart file, all goals were achieved successfully as shown in figure 7 and 8.
Figure 7: Final Results
Figure 8: Debug Console Log
Luckily, Mr. X has placed the full source code available here⁹.
Note: If you’re interested to test this app, follow the below link.
: Dart Packages
: Elevated Button Class
: Simple Dialog Class
: CheckboxListTile Class
: Align Class
: Map<K, V>.fromIterable Constructor
: FormField<T> Class
:Full Source Code