Search code examples
jsonflutterdartdart-pub

How can i pass this complex Json MAP Data into flutter Listview


i am new to flutter, and i meet this API with complex "MAP" json. What i want is to display the list of countries with their details in flutter listview, How can i achieve that? Most of answers explain about "LIST" json.

 {
"status": "Request is successful",
"message": null,
"data": {
"page": 1,
"last_page": 125,
"page_size": 2,
"countries": [
        {
 "id": "1",
"attributes": {
"name": "Grenada",
 "code": "GD",
"subregion": "Caribbean",
"flag": "https://flagcdn.com/gd.svg",
"postalcode": "",
"latitude": "12.11666666",
"longitude": "-61.66666666",
"createdAt": "2023-01-11T22:15:40.000000Z",
"updatedAt": "2023-01-11T22:15:40.000000Z"
  }
 },
  {
"id": "2",
"attributes": {
 "name": "Malaysia",
 "code": "MY",
 "subregion": "South-Eastern Asia",
 "flag": "https://flagcdn.com/my.svg",
  "postalcode": "^(\\d{5})$",
 "latitude": "2.5",
  "longitude": "112.5",
  "createdAt": "2023-01-11T22:15:40.000000Z",
  "updatedAt": "2023-01-11T22:15:40.000000Z"
     }
     }
  ]
  }
  }

I found this GitHub project with these files json, modelClass Mainclass which relate with the concept but mine is has got one extra braces (map) so i do not know how to achieve the goal.

if there any suggestion or best way to code please help me.

this is how they created in model class but, but it does not work with me.

    class Product {
   final List<Result> results;
    Product({this.results});
    factory Product.fromJson(Map<String, dynamic> data) {
     var list = data['data']['result'] as List;
    List<Result> resultList = list.map((e) => Result.fromJson(e)).toList();
    return Product(
    results: resultList,
    );
    }
    }  

what i have done is

       class MyStatefulWidget extends StatefulWidget {
      const MyStatefulWidget({super.key});

       @override
     State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
         }
      class _MyStatefulWidgetState extends State<MyStatefulWidget> {
     var data_from_link;
      getData() async {
      final String link = 'myurl';
      data_from_link = await http.get(Uri.parse(link), headers:    {"Accept": "application/json"});
     final res = jsonDecode(data_from_link.body) as Map<String, dynamic>;
        final List<Country> list= (res['data']['countries'] as      List<dynamic>).map((e) => Country.fromJson(e))
    .toList();
  
          }

        @override
        void initState() {
           super.initState();
                 getData();
                  }
          @override
             Widget build(BuildContext context) {
             final res = jsonDecode(data_from_link.body) as Map<String, dynamic>;
             final List<Country> list= (res['data']['countries'] as  List<dynamic>).map((e) => Country.fromJson(e))
          .toList();
        return  ListView.builder(
            itemCount: list.length,
         itemBuilder: (_, i) => ListTile(
               title: Text(
                 list![i].attributes.name,
             ),
               subtitle: Text(list![i].attributes.code),
                 )
                 );
                }
               }

Solution

  • You can create two classes for Country and Attribute

    class Country {
      const Country({required this.id, required this.attributes});
    
      /// Creates a Country from Json map
      factory Country.fromJson(Map<String, dynamic> json) => Country(
            id: json['id'] as String,
            attribute:
                Attribute.fromJson(json['attributes'] as Map<String, dynamic>),
          );
    
      /// A description for id
      final String id;
      final Attribute attributes;
    }
    
    class Attribute {
      const Attribute({
        required this.name,
        required this.code,
        required this.createdAt,
        required this.updatedAt,
      });
    
      /// Creates a Attribute from Json map
      factory Attribute.fromJson(Map<String, dynamic> json) => Attribute(
            name: json['name'] as String,
            code: json['code'] as String,
            createdAt: DateTime.parse(json['createdAt'] as String),
            updatedAt: DateTime.parse(json['updatedAt'] as String),
          );
    
      final String name;
      final String code;
      final DateTime createdAt;
      final DateTime updatedAt;
    }
    
    

    when decoding:

      final res = jsonDecode(json) as Map<String, dynamic>;
      final List<Country> list = (res['data']['countries'] as 
      List<dynamic>)
            .map((e) => Country.fromJson(e))
            .toList();
    
    

    Thank you but how can i print or call data from country attribute after decoding because when i try something like Print (list.country.attribute.name) . I fail. My goal is to display on Listview

    You can use it like this:

    ListView.builder(
              itemCount: list.length,
              itemBuilder: (_, i) => ListTile(
                    title: Text(
                      list[i].attributes.name,
                    ),
                    subtitle: Text(list[i].attributes.code),
                  )),
    

    enter image description here

    UPDATE

    import 'package:flutter/material.dart';
    
    class MyStatefulWidget extends StatefulWidget {
      const MyStatefulWidget({super.key});
    
      @override
      State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
    }
    
    class _MyStatefulWidgetState extends State<MyStatefulWidget> {
      late Future<List<Country>> futureList;
      Future<List<Country>?> getData() async {
        final String link = 'yoururl';
        final res = await http
            .get(Uri.parse(link), headers: {"Accept": "application/json"});
        if (response.statusCode == 200) {
          final List<Country> list = (res['data']['countries'] as List<dynamic>)
              .map((e) => Country.fromJson(e))
              .toList();
          return list;
        } else {
          throw Exception('Failed to fetch data');
        }
      }
    
      @override
      void initState() {
        super.initState();
        futureList = getData();
      }
    
      @override
      Widget build(BuildContext context) {
        return FutureBuilder(
          future: futureList,
          builder: (context, snapshot) {
            if (snapshot.hasData) {
              final list = snapshot.data;
              return ListView.builder(
                itemCount: list!.length,
                itemBuilder: (_, i) => ListTile(
                  title: Text(
                    list![i].attributes.name,
                  ),
                  subtitle: Text(list![i].attributes.code),
                ),
              );
            } else if (snapshot.hasError) {
              return const Text('error fetching data');
            }
            return const CircularProgressIndicator();
          },
        );
      }
    }