How to code dropdowns that depend on other dropdowns – using Flutter

Issue

I have two Flutter dropdowns. The first loads a list of universities from a database and works perfectly. The second loads campuses for the selected university from a database.

At the moment I am using setState() from the onChanged() function of the university dropdown which works 80% of the time. The other 20% seems to be caused by a slow network whereby the dropdown hasn’t had time to fill before the screen refreshes, leaving it empty. If the university dropdown is clicked once, twice or three times the campuses dropdown will usually fill. Here is the loading code (where loadDatabaseSubTable() fills the campus dropdown:

 Container(
      decoration: new BoxDecoration(
        border: Border.all(width: 1),
        borderRadius: new BorderRadius.all(Radius.circular(5.0)),
        shape: BoxShape.rectangle,
      ),
      padding: EdgeInsets.symmetric(
          horizontal: kContainerPaddingHorizontal,
          vertical: kContainerPaddingVertical),
      child: DropdownButton<String>(
       hint: Text('Select the Institution'),
        value: selectedInstitute,
        underline: Container(
          height: 0,
        ),
        onChanged: (String value) {
          // Use setState() to load next dropdown
          if (institutionBefore != value) {
              setState(() {
              // Get matching campuses
              dropCampus = [];
              campusBuild.institutionId = shInstitutionId;
              campusBuild.campusId = '';
              loadDatabaseSubTable(
                  tableName: 'sa_campus_by_institute',
                  listVariable: dropCampus,
                  object: campusBuild);
              //
              selectedInstitute = value;
            });
          }
        },
        items: dropInstitution.map((String description) {
          return DropdownMenuItem<String>(
            value: description,
            child: Text(
              description,
              style: TextStyle(color: Colors.black),
            ),
          );
        }).toList(),
      ),
    ),

Is the above method the correct way of going about this? If so how can I make sure the refresh doesn’t occur before the dropdown has filled?

Or is it better to use a FutureBuilder to handle it?

I had thought to load all the campuses for all universities into memory first – but for an Android App. this seems like overkill on bandwidth usage.

I have another screen which has 6 dropdowns, each dependent on the previous one – using a FutureBuilder for each seems like a very untidy way of processing the dropdowns. Thanks in advance.

Solution

The problem is that loadDatabaseSubTable is async and you’re not waiting for it finish so by the time it fetches the data your setState would have been executed.

You need to change the onChanged to be async:

onChanged: (String value) async {

and then await the loadDatabaseSubTable:

await loadDatabaseSubTable(
  tableName: 'sa_campus_by_institute',
  listVariable: dropCampus,
  object: campusBuild);

See also

Answered By – Sami Haddad

Answer Checked By – Candace Johnson (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *