Home > Net >  Expected a value of type 'String', but got one of type 'List<dynamic>' for
Expected a value of type 'String', but got one of type 'List<dynamic>' for

Time:06-24

Got an API call that returns a bunch of data for my app. This particular data set is a Map<String, List<dynamic>>, I'm processing this data to make it usable within my app and passing it around to necessary widgets. I came across his error which makes no sense to me but it is self-explanatory looking at the code I cant see anything.

This code is a part of a bigger code please comment if you want me to add it as it just takes in a few arguments to process the Future and create the Map<String, List<dynamic>>.

This is the code where the error is being thrown (Line:45)

@override
  Widget build(BuildContext context) {
    return FutureBuilder<Map<String, List<dynamic>>>(
      future: options,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done &&
            snapshot.hasData) {
          return ListView.builder(
            scrollDirection: Axis.vertical,
            shrinkWrap: true,
            itemCount: snapshot.data!.values.length,
            itemBuilder: ((context, index) {
              return DropdownMenu(items: snapshot.data!.values.toList()); //Line: 45
            }),
          );
        } else if (snapshot.hasError) {
          return Text(snapshot.error.toString());
        } else {
          return const CircularProgressIndicator();
        }
      },
    );
  }

This is my DropdownMenu Class

class DropdownMenu extends StatefulWidget {
  DropdownMenu({super.key, required this.items});

  List<dynamic> items;

  @override
  State<DropdownMenu> createState() => _DropdownMenuState(items);
}

class _DropdownMenuState extends State<DropdownMenu> {
  _DropdownMenuState(this.items);

  String? value;
  List<dynamic> items;

  @override
  void initState() {
    super.initState();
    widget.items = items;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4),
      decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(12),
          border: Border.all(color: Colors.black, width: 2)),
      child: DropdownButtonHideUnderline(
        child: DropdownButton<dynamic>(
          value: value,
          onChanged: (value) => setState(() => this.value = value),
          items: items.map(buildMenuItem).toList(),
        ),
      ),
    );
  }

  DropdownMenuItem<dynamic> buildMenuItem(dynamic item) => DropdownMenuItem(
        value: item,
        child: Text(
          item,
          style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
        ),
      );
}

Error

The following TypeErrorImpl was thrown building DropdownMenu(dirty, state:
_DropdownMenuState#69c5b):
Expected a value of type 'String', but got one of type 'List<dynamic>'
The relevant error-causing widget was:
  DropdownMenu
DropdownMenu:file:///C:/Main Storage/_GitHub Repos/flutter_fontend_client/lib/components/options__dropdown_menu.dart:45:22

After some debugging... I added this piece of code

var result1 = {
  for (var value in snapshot.data!.values.toList())
    value.first: value
};
print("Values of the snapshot: $result1");

The result is a big awkward and IDK why it like this. It prints out a json style format string {'key': ['keyStrings', 'keyStrings']

Got a different answer from someone in NorDev Discord.

I will show the answer here keep the accepted answer as both work and I think that people will appreciate that there is multiple ways of solving this.

return DropdownMenu(items: snapshot.data!.values.elementAt(index));

CodePudding user response:

According to your code, your response is a Map with strings as keys and List as values. That means that snapshot.data!.values.toList() is a list with (possibly) multiple List<dynamic> that you are passing to DropdownMenu.

DropdownMenu expects that the elements of the list are of type String but they are not.

I suspect what you want to do is actually get the first list, so you could do

return DropdownMenu(items: snapshot.data!.values.first);
  • Related