22

I have a dropdown button which works fine, but when I try to set a default value it will fail with the following error:

'package:flutter/src/material/dropdown.dart': Failed assertion: line 620 pos 15: 'items == null || items.isEmpty || value == null || items.where((DropdownMenuItem item) => item.value == value).length == 1': is not true.

This is my dropdown button:

 Widget changeWorkspace() {
return StatefulBuilder(
    builder: (BuildContext context, StateSetter setState) {
  return Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
    Padding(
      padding: EdgeInsets.all(8.0),
      child: DropdownButton<AssignedWorkspace>(
          isExpanded: true,
          hint: Text("SELECT WORKSPACE"),
          value: selectedWorkspace,
          onChanged: (dropdownValueSelected) {
            setState(() {
              selectedWorkspace = dropdownValueSelected;
            });
          },
          items: workspaces != null && workspaces.length > 0
              ? workspaces.map((AssignedWorkspace workspace) {
                  return new DropdownMenuItem<AssignedWorkspace>(
                    value: workspace,
                    child: new Text(workspace.name,
                        style: new TextStyle(color: Colors.black)),
                  );
                }).toList()
              : null),
    ),
  ]);
});

}

I've tried to set the value of selectedWorkspace onInit as follows but it fails.

selectedWorkspace = new AssignedWorkspace(
id: userSettings.currentWorkspaceId,
name: userSettings.currentWorkspaceName);

Is there a way of setting a default value in a dropdown button?

6 Answers 6

22
import 'package:flutter/material.dart';

import '../config/app_theme.dart';

class DropdownWidget extends StatefulWidget {
  final String title;
  final List<String> items;
  final ValueChanged<String> itemCallBack;
  final String currentItem;
  final String hintText;

  DropdownWidget({
    this.title,
    this.items,
    this.itemCallBack,
    this.currentItem,
    this.hintText,
  });

  @override
  State<StatefulWidget> createState() => _DropdownState(currentItem);
}

class _DropdownState extends State<DropdownWidget> {
  List<DropdownMenuItem<String>> dropDownItems = [];
  String currentItem;
  AppTheme appTheme;

  _DropdownState(this.currentItem);

  @override
  void initState() {
    super.initState();
    for (String item in widget.items) {
      dropDownItems.add(DropdownMenuItem(
        value: item,
        child: Text(
          item,
          style: TextStyle(
            fontSize: 16,
          ),
        ),
      ));
    }
  }

  @override
  void didUpdateWidget(DropdownWidget oldWidget) {
    if (this.currentItem != widget.currentItem) {
      setState(() {
        this.currentItem = widget.currentItem;
      });
    }
    super.didUpdateWidget(oldWidget);
  }

  @override
  Widget build(BuildContext context) {
    appTheme = AppTheme(Theme.of(context).brightness);

    return Container(
      margin: EdgeInsets.symmetric(vertical: 10),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          Container(
            margin: EdgeInsets.only(left: 6),
            child: Text(
              widget.title,
              style: appTheme.activityAddPageTextStyle,
            ),
          ),
          Container(
            padding: EdgeInsets.symmetric(vertical: 3, horizontal: 15),
            margin: EdgeInsets.only(top: 10),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(6),
              color: Colors.white,
              boxShadow: [
                BoxShadow(
                  offset: Offset(0, 2),
                  blurRadius: 10,
                  color: Color(0x19000000),
                ),
              ],
            ),
            child: DropdownButtonHideUnderline(
              child: DropdownButton(
                icon: appTheme.activityAddPageDownArrowSVG,
                value: currentItem,
                isExpanded: true,
                items: dropDownItems,
                onChanged: (selectedItem) => setState(() {
                  currentItem = selectedItem;
                  widget.itemCallBack(currentItem);
                }),
                hint: Container(
                  child: Text(widget.hintText, style: appTheme.hintStyle),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

This is my dropDownWidget without optimization. It has currentItem. You could use it like:

           DropdownWidget(
                title: kStatus,
                items: state.customerStepInfo.statusList,
                currentItem: status,
                hintText: kCommonPick,
                itemCallBack: (String status) {
                  this.status = status;
                },
              )
Sign up to request clarification or add additional context in comments.

4 Comments

An explanation would be nice.
This code will generate the warning, “Don’t put any logic in createState”.
All magic in @override void didUpdateWidget. Its update Widget after build state. (see: flutterbyexample.com/lesson/stateful-widget-lifecycle). Doesn't look like good practice.
Where is AppTheme defined? An explanation of key parts of code would be nice.
4

You need implement "equals" in class AssignedWorkspace. I used equatable package.

Example class AssignedWorkspace

class AssignedWorkspace extends Equatable {
  final String id;
  final String name;

  AssignedWorkspace(this.id, this.name);
   
  @override
  List<Object> get props => [id];
}

3 Comments

i didn't unsderstamd why do youd did that?please explain more
@Mehrdad because when assigning instance class as a value, then you must overload the equals to correctly evaluate if two instances are equal. with this you don't need to have another state (like currentItem in the top voted example). Only instances of the AssignedWorkspace class.
That's a nice answer, actually solving the issue from the root level. Thanks :)
1

I changed the value of the dropdown var to 1 initially var _value = '1'; So when the dropdown button has to display its value it displays the one whose value I have set 1 as in the items list in DropDownButton

DropdownButton(
                underline: Container(),
                onChanged: (value) {
                  setState(() {
                    _value = value;
                  });
                },
                value: _value,
                items: [
                  DropdownMenuItem(
                    value: "1",
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: <Widget>[
                        Icon(MaterialCommunityIcons.devices),
                        SizedBox(width: 10),
                        Text(
                          "Consumption",
                          style: TextStyle(
                              fontSize: 18.0, fontWeight: FontWeight.w600),
                        ),
                      ],
                    ),
                  ),
                  DropdownMenuItem(
                    value: "2",
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: <Widget>[
                        Icon(MaterialCommunityIcons.solar_panel),
                        SizedBox(width: 10),
                        Text(
                          "Generation",
                          style: TextStyle(
                              fontSize: 18.0, fontWeight: FontWeight.w600),
                        ),
                      ],
                    ),
                  ),
                ],
              ),

2 Comments

Please can you add your questions the name of the SDK ?
Its flutter SDK
0

For me id of one of the element is null, once added id is made non-null issue got fixed.

1 Comment

Can you explain, or put some example when is one of element null
0

if you want to see only an initial value you can use hint text named parameter of drop down button and set a text widget. i dont know whether it is a good practice or not.

Comments

-2
 DropdownButtonFormField(
          value: '12',
          isExpanded: true,
          icon: const HeroIcon(
            HeroIcons.chevronDown,
            // solid: true,
            color: Color(0xff656565),
            size: 30,
          ),
          decoration: InputDecoration(
            fillColor: Colors.white,
            contentPadding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
            ),
            focusedBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: const BorderSide(
                color: Colors.grey,
              ),
            ),
            enabledBorder: OutlineInputBorder(
              borderRadius: BorderRadius.circular(8),
              borderSide: const BorderSide(
                color: Colors.grey,
              ),
            ),
          ),
          style: tBodyTextNew,
          onChanged: (value) {
            print(value);
            controller.provinsi.value = int.parse(value.toString());
            kabupaten.kabupaten(req: value);
          },
          items: controller.listProvice.map((value) {
            return DropdownMenuItem<String>(
              value: value.idwilayahProvinsi.toString(),
              child: Text(
                value.namaProvinsi,
                style: tBodyTextNew,
              ),
            );
          }).toList(),
        ),

convert value to string

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.