Setting DropdownButton Initial Value in Flutter

66 Views Asked by At

I have a list of an object that could have 0+ records. If a record exists, I have a DropdownButton that I want to pre-populate with the first record in the list. Then, when the user changes it, leaves the screen, and comes back, it keeps the selected option.

If the list is empty, I don't want to display the DropdownButton at all; I want an alternate message (but that's for another day).

However, I cannot get the DropdownButton to populate with the first record in the list.

Here is the object class:

class Team {
  const Team(this.id, this.name);

  final int id;
  final String name;
}

Here is the list of records:

List<Team> myTeams = <Team>[
  const Team(1, 'Eagles'),
  const Team(2, 'Bobcats')
];

Here is the State class:

class MyAppState extends ChangeNotifier {
  Team? myTeam;
  var myTeamId;
  String? myTeamName;

  void setTeam(Team? selectedValue) {
    myTeam = selectedValue;
    myTeamId = selectedValue?.id;
    myTeamName = selectedValue?.name;
    notifyListeners();
  }
}

Here is the page with the DropdownButton:

class GeneratorPage extends StatefulWidget {
  @override
  State<GeneratorPage> createState() => _GeneratorPageState();
}

class _GeneratorPageState extends State<GeneratorPage> {
  Team? selectedTeam;
  //List<Team> myTeams = <Team>[const Team(1, 'Eagles'), const Team(2, 'Bobcats')];

  @override
  void initState() {
    super.initState();
    selectedTeam = myTeams[0];
  }

  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();
    var selectedTeam = appState.myTeam;

    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          DropdownButton<Team>(
            value: selectedTeam,
            onChanged: (Team? newValue) {
              setState(() {
                appState.setTeam(newValue);
              });
            },
            items: myTeams.map((Team user) {
              return DropdownMenuItem<Team>(
                  value: user, child: Text(user.name));
            }).toList(),
            icon: const Icon(Icons.arrow_downward),
            elevation: 16,
            style: const TextStyle(color: Colors.deepPurple),
            underline: Container(
              height: 2,
              color: Colors.deepPurpleAccent,
            ),
          ),
        ],
      ),
    );
  }
}

Here is the page with the empty DropdownButton when the app loads:

App home page with empty DropdownButton

To reiterate, once the user selects an option from the DropdownButton, it works fine going back and forth between screens. I just can't get it to pre-populate. I am new to Flutter/Dart, so I apologize if this is a simple solution.

2

There are 2 best solutions below

0
On BEST ANSWER

Figured it out. I just needed to change the 1st line in MyAppState:

class MyAppState extends ChangeNotifier {
  Team? myTeam = myTeams.first; // OLD: Team? myTeam;
  var myTeamId;
  String? myTeamName;

  void setTeam(Team? selectedValue) {
    myTeam = selectedValue;
    myTeamId = selectedValue?.id;
    myTeamName = selectedValue?.name;
    notifyListeners();
  }
}

So I was updating myTeam in the setTeam() function upon an action, but I was never giving myTeam an initial value if it existed.

2
On

The setTeam method within the MyAppState class appears well-structured, effectively updating myTeam, myTeamId, and myTeamName variables upon selection.

I observed that myTeam is already a part of the state. Consequently, in your _GeneratorPageState class, there's no necessity for an additional local variable named selectedTeam. Instead, you can seamlessly utilize appState.myTeam directly to both retrieve and update the selected team.

You can remove the local variable and use the class-level variable directly.

Here's a modified version of your _GeneratorPageState class:

class _GeneratorPageState extends State<GeneratorPage> {
  @override
  Widget build(BuildContext context) {
    var appState = context.watch<MyAppState>();

    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          DropdownButton<Team>(
            value: appState.myTeam,
            onChanged: (Team? newValue) {
              setState(() {
                appState.setTeam(newValue);
              });
            },
            items: appState.myTeams.map((Team user) {
              return DropdownMenuItem<Team>(
                  value: user, child: Text(user.name));
            }).toList(),
            icon: const Icon(Icons.arrow_downward),
            elevation: 16,
            style: const TextStyle(color: Colors.deepPurple),
            underline: Container(
              height: 2,
              color: Colors.deepPurpleAccent,
            ),
          ),
        ],
      ),
    );
  }
}

Try these changes, and it should help prepopulate the value of the dropdown correctly.