Let’s create a two level-dependent dropdown with flutter. We will use data from this Nigerian location API, specifically the states and local government council areas data. Every state has many local governments councils. The first drop down will contain the states and on a selection of a state item, it will populate the second dropdown with its local councils.

The sample data from http://locationsng-api.herokuapp.com/api/v1/lgas looks like this:

In this episode, we will not make API calls rather save the file and read it locally.

Getting Started

$ flutter create multi_level_dropdown $ cd multi_level_dropdown

Inside the lib folder, create a new file named repository.dart. This file will act as the local data source. Just in case you prefer to make calls to API endpoint above you can swap the getAll() method (which we have not created yet). Grab the entire JSON returned from http://locationsng-api.herokuapp.com/api/v1/lgas, yes the FAT JSON and save it as a Dart List. Also create three methods named getAll(), getStates() and getLocalByState(String state) to fetch all data, list of states and list of local councils by for a given state respectively. See the abridged version below

Data model

Before implementing the functions, let’s make a class to represent each of the state JSON items. You don’t have to do this. It’s my preferences, I like to manipulate the states as objects instead of maps. And when you chose this route, you don’t have to type this yourself you can use this tool JSON to Dart. Take any of the state items from the JSON and paste on that tool, then click on Generate Dart button. Inspect the generated code and make the needed adjustments. Here is my code and save as state_model.dart

A simple class with two factory methods toJson() and fromJSON(). Both do what their names imply: converts to and from the JSON we saved from the API endpoint.

So back to the repository.dart file, we should implement the pending methods.

The first line imports the StateModel class so we can use the fromJson() method.

getAll() simply returns the ‘FAT’ List that contains the state maps. The getStates() method simply transform each state map to a StateModel object, then transform the collection to a list of states. The result of that method call will be:

['Adamawa', 'Akwa Ibom', 'Edo',...]

getLocalByState(String state) method take a state argument and returns a list of its local councils. The first map() function transforms each state map to a StateModel object, the where() function filters the collection by the given state, the next map function transforms it to only the ‘lgas’ ( the local council property, which in this case is a list). At this point the result is a List of collection, we use expand((i) => i) to flatten the collection and finally returns a list of local councils. The result for getLocalByState(‘Edo’) will be

['Akoko Edo', 'Estako East', ...]

Alright!, we are done with our data source. Let's build the dependent dropdown

Dropdown widgets

Open the main.dart file and replace the content with the code below

Next, create the Home stateful widget

Add some fields with initial data inside the HomeState class

Repository repo = Repository(); List<String> _states = ["Choose a state"]; List<String> _lgas = ["Choose .."]; String _selectedState = "Choose a state"; String _selectedLGA = "Choose ..";

_states will hold the list of states from the getStates() method, _lgas will hold data from getLocalsBy State(state), _selectedState and _selectedLGA represent the current item for each dropdown menu.

Next override the initState() method. We want the list of states preloaded before the widget is rendered.

_states = List.from(_states)..addAll(repo.getStates()) prepends the initial value of _states to repo.getStates()

Next, we will make the dropdowns. Flutter has DropdownButton widget, with an items property that takes a list of DropdownMenuItem. So inside build method include the following

We added some padding to the container and a child Column widget with a list of DropdownButton Children. The first dropdown items property is given below

items: _states.map((String dropDownStringItem) { return DropdownMenuItem<String>( value: dropDownStringItem, child: Text(dropDownStringItem), ); }).toList(),

maps over _states list and returns a list of DropdownMenuItem. Similarly the second maps over _lgas list and return a list of DropdownMenuItem. Both have e their default values defined and set to the fields defined earlier in the class.

The next two areas are the functions called by the onChange property of both DropdownButton: onChanged: (value) => _onSelectedState(value) and onChanged: (value) => _onSelectedLGA(value)

_onSelectedState method does the following sets values for _selectedLGA ,_lgas and _selectedState. Then append the result of repo.getLocalByState(value) to _lgas list. All these are done inside the setState() method.

_onSelectedLGA method simply sets the current value of the dropdown button to the selected item.

That seems about it. Save your changes, start your emulator and run the application

flutter run

You should see the result

Initial state

On selecting Edo state

Thank you for your time guys. Let me know if you find errors, typos or better ways to do this. You can hit me up on Twitter @afegbuas

Github code repo: https://github.com/shubie/Multi-Level-Dependent-Dropdown

You can read the rest of Flutter Thursday series here: https://medium.com/@afegbua/flutter-thursday-series-9564d04e63a7