Search code examples
jsonflutterdartserializablemobile-development

How do I populate a GridView by traversing a JSON array in Flutter the JSON_Serializable way?


I'm trying to parse an array of JSON Objects to populate a GridView in Flutter. So far, I can only get a single object, but can't traverse the whole array of objects.

JSON String: A list of Beef recipe objects within 'beef' array.

My code:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class SpecificCategoryPage extends StatefulWidget {
  late final String category;

  SpecificCategoryPage({Key? key, required this.category}) : super(key: key);

  @override
  _SpecificCategoryPageState createState() => _SpecificCategoryPageState();
}

class _SpecificCategoryPageState extends State<SpecificCategoryPage> {
  late Future<Meal> meals;
  late List<Widget> mealCards;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<Meal>(
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return Text(
                'Truest\nId: ${snapshot.data!.id}. ${snapshot.data!.meal}');
          } else {
            return Text('${snapshot.error}');
          }
          // Be default, show a loading spinner.
          return CircularProgressIndicator();
        },
        future: meals,
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    meals = _fetchMeals();
  }

  Future<Meal> _fetchMeals() async {
    final http.Response mealsData = await http.get(
        Uri.parse('https://www.themealdb.com/api/json/v1/1/filter.php?c=Beef'));
        if (mealsData.statusCode == 200)
          return Meal.fromJson(jsonDecode(mealsData.body));
        else
          throw Exception('Failed to load meals');
    }

class Meal {
  final String? id, meal;

  Meal({required this.id, required this.meal});

  factory Meal.fromJson(Map<String, dynamic> json) {
    return Meal(
        id: json['meals'][0]['idMeal'], meal: json['meals'][0]['strMeal']);
  }
}

Sample object traversal path:

{"meals":[{"strMeal":"Beef and Mustard Pie","strMealThumb":"https:\/\/www.themealdb.com\/images\/media\/meals\/sytuqu1511553755.jpg","idMeal":"52874"}, {object1}, {object2}]}

What I'm getting:

{"strMeal":"Beef and Mustard Pie","strMealThumb":"https://www.themealdb.com/images/media/meals/sytuqu1511553755.jpg","idMeal":"52874"}

How do I get all objects in the array and inflate the GridView widget?


Solution

  • import 'dart:convert';
    
    // First you should create a model to represent a meal
    class Meal {
      
      // Place all the meal properties here
      final String strMeal;
      final String strMealThumb;
      final String idMeal;
    
      // Create a constructor that accepts all properties. They can be required or not
      Meal({
        required this.strMeal,
        required this.strMealThumb,
        required this.idMeal,
      });
    
      // Create a method (or factory constructor to populate the object based on a json input)
      factory Meal.fromJson(Map<String, dynamic> json) => Meal(
            strMeal: json['strMeal'],
            strMealThumb: json['strMealThumb'],
            idMeal: json['idMeal'],
          );
      
      String toString() {
        return 'strMeal: $strMeal, strMealThumb: $strMealThumb, idMeal: $idMeal';
      }
    }
    
    /// Then you should create another object to represent your response
    /// It holds a list of meals that'll be populated by your API response
    
    class YourAPIResponse {
      final List<Meal> meals;
    
      YourAPIResponse({required this.meals});
    
      factory YourAPIResponse.fromJson(Map<String, dynamic> json) =>
          YourAPIResponse(
            meals: List<Meal>.from(
              json['meals'].map((meal) => Meal.fromJson(meal)),
            ),
          );
    }
    
    void main() {
      // Test data: This will be your API response
      String jsonString = '{"meals": [{"strMeal": "Beef and Mustard Pie","strMealThumb": "https://www.themealdb.com/images/media/meals/sytuqu1511553755.jpg","idMeal": "52874"}]}';
      
      final apiResponse = YourAPIResponse.fromJson(json.decode(jsonString));
      
      // Your meals list
      // You can use this to populate the gridview
      print(apiResponse.meals);
    }