'Can't convert Map to List in Dart, facing "Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>" error

I know this question has been asked, but I'll explain my problem and show you what I've tried.

So, I receive a response from an API, that looks exactly like this:

[
    {
        "id": 1,
        "nome": "Macarrão",
        "descricao": "Macarrão Parafuso 100g",
        "preco": 10.23,
        "imagem": "https://www.-------.com.br/ccstore/v1/images/?source=/file/v3396941523676425853/products/141618_0.jpg"
    },
    {
        "id": 2,
        "nome": "Nescau",
        "descricao": "Achocolatado Nescau",
        "preco": 5.23,
        "imagem": "https://www.-------.com.br/ccstore/v1/images/?source=/file/v3396941523676425853/products/141618_0.jpg"
    },
    {
        "id": 3,
        "nome": "Toddynho",
        "descricao": "Bedida láctea - Toddynho",
        "preco": 2.48,
        "imagem": "https://www.-------.com.br/ccstore/v1/images/?source=/file/v3396941523676425853/products/141618_0.jpg"
    },
    {
        "id": 4,
        "nome": "Toddynho",
        "descricao": "Bedida láctea - Toddynho",
        "preco": 2.48,
        "imagem": "https://www.-----.com.br/ccstore/v1/images/?source=/file/v3396941523676425853/products/141618_0.jpg"
    }
]

Those are products that have 5 attributes, and I want to display them(the products) on screen. Right now my code looks like this:

Future<void> loadProducts() async {
    final response = await http.get(Uri.parse(_url));
    if (response.body == null) return;
    Map<String, dynamic> data = jsonDecode(response.body);
    print(response.body);
    data.forEach((productId, productData) {
      _items.add(
        Product(
          id: productId,
          nome: productData['nome'],
          descricao: productData['descricao'],
          preco: productData['preco'],
          imagem: productData['imagem'],
        ),
      );
    });

    notifyListeners();
  }

Product is

class Product with ChangeNotifier {
  final String id;
  final String nome;
  final String descricao;
  final double preco;
  final String imagem;
  bool isFavorite;

  Product({
    required this.id,
    required this.nome,
    required this.descricao,
    required this.preco,
    required this.imagem,
    this.isFavorite = false,
  });

  void toggleFavorite() {
    isFavorite = !isFavorite;
    notifyListeners();
  }
}

and I have tried solutions like this:

List<String> respApi =
        (jsonDecode(response.body) as List<dynamic>).cast<String>();

from this answer , or this one

var usersDataFromJson = parsedJson['data'];
List<String> userData = List<String>.from(usersDataFromJson);

that would result in the error The argument type 'void Function(String, dynamic)' can't be assigned to the parameter type 'void Function(String)'.

Thanks again for your help.



Solution 1:[1]

I think you get the error on the line _items.add. So based on te code in my previous answer it should be like this

_items.add( 
   Product(
      id: element['id'] ,
      nome: element['nome'],
      descricao: element['descricao'],
      preco: element['preco'],
      imagem: element['imagem'],
    )
)

and you don't need to use forEach anymore. Also for your Product class I advice you declare id of type int instead of String to avoid errors since in your json id is an int.

Solution 2:[2]

If you look at your json, you see it's a List of Map, but on this line:

Map<String, dynamic> data = jsonDecode(response.body);

you are putting it inside a Map so it's logic to get an error. To resolve the error, do this:

List<Map> data  = jsonDecode(response.body);
// or 
// List<Map<String, dynamic>> data = jsonDecode(response.body) ;

But if it throws TypeError, do this instead:

List data = jsonDecode(response.body);

And you can access your data like this:

for(var element in data) {
   element.forEach((k,v) {
      //operations
   }) ;
} 

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2