Christian Giupponi
Christian Giupponi

Reputation: 7618

Dart - Convert json to a typed list

I'm working on a recipes app and I have an endpoint that returns all the data and an array with all the ingredients needed.
In my provider I fetch all the recipes with Recipes.fromJson and everything works fine, but I have some problems when need to fetch the ingredients array.

This is the ingredient json ( as part of a bigger json with all the recipes informations):

[{quantity: 1, unit: , ingredient: rortolo di pasta sfoglia rettangolare, notes: }, {quantity: 2, unit: , ingredient: patate, notes: ( o 1 o 3 dipende dalla grandezza delle patate)}, {quantity: qb, unit: , ingredient: pesto fresco, notes: potete farlo o comprarlo l'importante è che sia quello fresco}, {quantity: qb, unit: , ingredient: formaggio a scelta, notes: io ho usato emmental, evitate di scegliere formggi troppo molli farebbero solo poltiglia}, {quantity: 1, unit: , ingredient: tuorlo d'uovo, notes: }]

Ingredient:

import 'package:meta/meta.dart';

class Ingredient {
  final String quantity;
  final String unit;
  final String ingredient;
  final String note;

  Ingredient({
    @required this.quantity,
    @required this.ingredient,
    this.unit,
    this.note,
  });

  factory Ingredient.fromJson(Map<String, dynamic> json) {
    return Ingredient(
      ingredient: json['ingredient'] ?? '',
      quantity: json['quantity'] ?? '',
      unit: json['unit'] ?? '',
      note: json['note'] ?? null,
    );
  }
}

And this is the Recipe.fromJson, in a Recipe model, where I try to fetch the ingredients and build a List with no success.

import 'dart:convert';

import 'package:meta/meta.dart';

import '../models/ingredient.dart';

class Recipe {
  final int id;
  final String title;
  final String intro;
  final String difficulty;
  final String cookingTime;
  final String featureImage;
  final String description;
  final String servings;
  final List<Ingredient> ingredients;

  Recipe({
    @required this.id,
    @required this.title,
    @required this.difficulty,
    @required this.cookingTime,
    @required this.featureImage,
    @required this.description,
    @required this.ingredients,
    @required this.servings,
    this.intro,
  });

  factory Recipe.fromJson(Map<String, dynamic> json) {
    var recipeIngredients = json['ingredients'];
    List<Ingredient> ingredients = recipeIngredients.map((i) {
      print(i);
      return Ingredient.fromJson(i);
    }).toList();

    return Recipe(
      id: json['id'] ?? null,
      title: json['title'] ?? '',
      difficulty: json['difficulty'] ?? 'facile',
      cookingTime: json['cooking_time'] ?? '',
      servings: json['servings'] ?? '',
      featureImage:
          json['featureImage'] ?? 'https://via.placeholder.com/1920x768',
      description: json['description'] ?? '',
      intro: json['intro'] ?? '',
      ingredients: ingredients,
    );
  }
}

NB: if I print recipeIngredients I get the json posted above.

If I run the code I get this error:

flutter: type 'List' is not a subtype of type 'List'

Any idea why?

EDIT:
This is what I get from the API:

[
   {
      "id":348,
      "title":"Spiedini di mazzancolle cocco e lime",
      "intro":"Oggi voglio proporvi una ricetta semplicissima da fare e da inserire in un buffet di antipasti. E' molto molto gustosa, dal sapore tropicale e conquister\u00e0 tutti i palati per la sua particolarit\u00e0 e il perfetto connubio tra gli ingredienti presenti nella ricetta.\r\n\r\nDai andiamo in cucina insieme vedrete che non resterete delusi",
      "featureImage":"https:\/\/example.it\/wp-content\/uploads\/2020\/12\/coccolime.jpeg",
      "difficulty":"Easy",
      "cooking_time":"30",
      "servings":"4",
      "ingredients":[
         {
            "quantity":"400",
            "unit":"g",
            "ingredient":"mazzancolle",
            "notes":"o se preferite gamberi"
         },
         {
            "quantity":"4 cucchiai",
            "unit":"",
            "ingredient":"farina di cocco",
            "notes":"(non cocco rap\u00e8 farina di cocco)"
         },
         {
            "quantity":"2 cucchiai ",
            "unit":"",
            "ingredient":"pangrattato",
            "notes":""
         },
         {
            "quantity":"1",
            "unit":"",
            "ingredient":"lime",
            "notes":""
         },
         {
            "quantity":"qb",
            "unit":"",
            "ingredient":"pepe rosa in grani da macinare al momento",
            "notes":""
         },
         {
            "quantity":"",
            "unit":"",
            "ingredient":"",
            "notes":""
         }
      ],
      "instructions":[
         {
            "image":"",
            "description":"La realizzazione di questa ricetta \u00e8 davvero molto semplice. Come prima cosa preriscaldate il forno a 180 gradi , preparate in un piatto il mix di farina di cocco, pepe rosa macinato al momento ( io uso un pepe rosa con macinino nel tappo che contiene pepe rosa e limone e d\u00e0 un tocco davvero molto speciale) e pan grattato, preparate anche un altro piatto con dentro il succo di un lime e pulite i gamberi togliendo il carapace "
         },
         {
            "image":"",
            "description":"Immergete adesso le mazzancolle nel piatto con il mix di farina di cocco,pan grattato e pepe rosa e girateli per bene in modo da infarinare tutte le mazzancolle"
         },
         {
            "image":"",
            "description":"Adesso immergeteli nel piatto col succo di lime e girateli velocemente per far prendere il succo a tutte le mazzancolle"
         },
         {
            "image":"",
            "description":"A questo punto rimetteteli nel piatto col mix di farina di cocco,pepe rosa e pan grattato e girateli di nuovo per far prendere la farina a tutte le mazzancolle"
         },
         {
            "image":"",
            "description":"Mettetele in un piatto e fateli riposare 5 minuti"
         },
         {
            "image":"",
            "description":"Adesso prendete gli spiedini e mettete 3 mazzancolle su ogni spiedino"
         },
         {
            "image":"",
            "description":"Prendete la teglia da forno coperta con carta da forno, disponete sopra gli spiedini e infornate a 180 gradi per 15 minuti"
         },
         {
            "image":"349",
            "description":"Sfornate, mettete su un piatto da portata e servite"
         }
      ]
   }
]

Upvotes: 0

Views: 155

Answers (2)

ch271828n
ch271828n

Reputation: 17597

(This is not a direct answer to the question; however, the question seems to be a A-B problem so this answer may help.)

You do not need to write fromJson manually. Instead, use json_serializable package, which will auto generate that.

That package handles many details quite well, such as the problem you meet. Actually, that will automatically generate mostly the same code you have written in your fromJson.

Upvotes: 0

Christian Giupponi
Christian Giupponi

Reputation: 7618

I have found the solution thanks to this answer: https://stackoverflow.com/a/61583933/345812

All I need to do is:

List<Ingredient> ingredients = List<Ingredient>.from(
        recipeIngredients.map((x) => Ingredient.fromJson(x)));

This will return the correct list

Upvotes: 2

Related Questions