0
votes

we have a flutter-project running and want to include a stateful widget with a dropdownmenu. We use SQflite as our database.

We have a list of profiles in our database and with the dropdown we want to select one of the profiles. This works fine.

The Problem:

We save the ID of the last profile selected in with SharedPreferences. Initially we want to have the profile with the last selected id (which we load from SharedPreferences) as the default value.

Our Dropdown-Menu inside a future-builder (of the list profilesFuture with type Future<List<Profile>>):

return new Container(
    child: DropdownButton<Profile>(
        items: snapshot.data.map((Profile item) {
            return DropdownMenuItem<Profile>(
                value: item,
                child: Text(item.caption + " (" + item.serverAddress + ")")
            );
        }).cast<DropdownMenuItem<Profile>>().toList(),
        onChanged: (Profile newSelectedProfile) {
            setState(() {
                selectedProfile = newSelectedProfile;
                PreferencesService.setLastProfileId(newSelectedProfile.id);
            });
        },
        value: selectedProfile,
    )
);

We initialize our state like this:

Future profilesFuture;
Profile selectedProfile;
Future prefService;
int lastProfileId;

@override
void initState() {
    profilesFuture = DatabaseService.db.getProfiles();

    super.initState();
    _getLastProfileId().then((value) => _getSelectedProfile(value));
}

Future<Profile> _getSelectedProfile(int id) async {
    Profile profile = await DatabaseService.db.getProfileById(id);
    setState(() {
      selectedProfile = profile;
    });
    return profile;
}

Future<int> _getLastProfileId() async {
    int profileId = await PreferencesService.getLastProfileId();
    setState(() {
      lastProfileId = profileId;
    });
    return profileId;
}

The Error

either zero or 2 or more dropdownmenuitems were detected with the same value. Assertion failed. There should be exactly one item with DropDownMenus value.

Further information: https://github.com/glutter-dev-team/glutter/blob/feature/profile-selector/lib/widgets/profile_selector.dart

The Question

Whats wrong with it? How to correctly initialize a DropDownMenu with async values. The Problem definitely is caused by the default value. Without initializing the value-parameter it works fine, but the initial state is not correct.

All we have to do is:

  1. Load the lastSelectedProfileId from SharedPreferences (async)
  2. Load the selectedProfile from the database-layer (async)
  3. Load the list of all profiles from the database-layer (async)
  4. Set the selectedProfile as default value and the list as dropdownmenu-items
2
We use a FutureBuilder to the profilesFuture (the list) around this like mentioned above. - MrzJkl
your error comes from github.com/flutter/flutter/blob/2783f8e2e1/packages/flutter/lib/… - most likely you dont have == operator and/or hashCode methods overriden in your Profile class - pskink
Should we override this? Because of what? And with what? - MrzJkl
because of this assert - there is a check: items.where((DropdownMenuItem<T> item) { return item.value == value; }).length == 1 - pskink
Okay, we´ve checked that. It solved our problem. Do you want to post this as an answer or should i do this by reference your comment? - MrzJkl

2 Answers

1
votes

Referring to @pskink this is the solution which solved our issue:

We have overridden the default == Operation in our Datamodel Profile.

bool operator == (dynamic other) =>
    other != null && other is Profile && this.id == other.id;

@override
int get hashCode => super.hashCode;
0
votes

You should check value must in items.value. What you are required to check in dropdown

    List<DropdownMenuItem<String>> _bankAccountType = [
    DropdownMenuItem(child: Text("--"), value: "--"),
    DropdownMenuItem(child: Text("Checking"), value: "Checking"),
    DropdownMenuItem(child: Text("Savings"), value: "Savings"),
  ];

DropdownButton<String>(
                      items: _bankAccountType,
                      iconSize: 0.0,
                      value: _bankAccountTypeValue,
                      onChanged: (value) {
                        setState(() {
                          _bankAccountTypeValue = value;
                        });
                        _checkBankAccountFormStatus();
                      }
                  ),

this will help you to fix the issue.