Gainz
Gainz

Reputation: 1799

How to Deserialize a list of objects from json in flutter

I am using the dart package json_serializable for json serialization. Looking at the flutter documentation it shows how to deserialize a single object as follow:

Future<Post> fetchPost() async {
  final response =
  await http.get('https://jsonplaceholder.typicode.com/posts/1');

  if (response.statusCode == 200) {
  // If the call to the server was successful, parse the JSON
  return Post.fromJson(json.decode(response.body));
  } else {
    // If that call was not successful, throw an error.
    throw Exception('Failed to load post');
  }
}

However, I am not familiar enough with dart to figure out how to do the same for a list of items instead of a single instance.

Upvotes: 163

Views: 237386

Answers (13)

Falchio
Falchio

Reputation: 606

Parse data class from json array:

import 'dart:convert';

...

final http.Response response = await http.get(uri, headers: headers);
if (response.statusCode == 200) {
      final List<dynamic> jsonArray = jsonDecode(response.body);
      final List<DataClass> data = jsonArray
                                   .map((jsonObject) => DataClass.fromJson(jsonObject))
                                   .toList(growable: false);
} 

Upvotes: 1

sudheer nunna
sudheer nunna

Reputation: 1719

Simply you can typecast your date like the below.

class SubCategories {
  String? id;
  String? name;
  String? detailsIcon;
  List<SubCategoriesList>? subCategorieslist = [];

  SubCategories(this.id, this.name, this.detailsIcon, this.subCategorieslist);

  SubCategories.fromJson(Map json) {
    id = json["_id"];
    detailsIcon = json["detailsIcon"];
    name = json["name"];
    json["subCategories"]!.forEach((v) {
      subCategorieslist!.add(SubCategoriesList.fromJson(v));
    });
    subCategorieslist = subCategorieslist;
  }
}

Upvotes: 1

Sebas
Sebas

Reputation: 31

What I did to solve the problem was the following:

List<YourItemClass> items = [];

final data = jsonDecode(resp.body); //Here it goes your json array

for (dynamic item in data) {
    items.add(YourItemClass.fromMap(item));
}

return items;

Of course you need to have a fromMap() method in YourItemClass, if you do not, you can get it in quicktype.io pasting one single json instance of your class (and selecting dart language).

Upvotes: 3

Noor Hossain
Noor Hossain

Reputation: 1831

Sometimes, the problem arise for the structure of JSON and for your Pojo class.

My JSON is as follows:

{"records":[{"name":"noor ","email":"email","mobileNo":187,"feedback":"good"}]}

According to this JSON we have to create the pojo classes right way. When you paste your JSON it will give you the pojo class in this site: https://javiercbk.github.io/json_to_dart/

You have to give a class name there. With name of question I found the following two pojo classes according to the above JSON:

class Questions {
  List<Records>? records;

  Questions({this.records});

  Questions.fromJson(Map<String, dynamic> json) {
    if (json['records'] != null) {
      records = <Records>[];
      json['records'].forEach((v) {
        records!.add(new Records.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.records != null) {
      data['records'] = this.records!.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

class Records {
  String? name;
  String? email;
  int? mobileNo;
  String? feedback;

  Records({this.name, this.email, this.mobileNo, this.feedback});

  Records.fromJson(Map<String, dynamic> json) {
    name = json['name'];
    email = json['email'];
    mobileNo = json['mobileNo'];
    feedback = json['feedback'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['name'] = this.name;
    data['email'] = this.email;
    data['mobileNo'] = this.mobileNo;
    data['feedback'] = this.feedback;
    return data;
  }
}

Now the important part: that convert that record to list. Here is the calling:

Future<List<Records>> getRecordList() async {
    return await http.get(Uri.parse(URL)).then((response) {
      print(response.body.toString());

      Questions questions = Questions.fromJson(json.decode(response.body));

     

      print(questions.records![0].feedback);

      List<Records> list_s = [];
      for (int i = 0; i < questions.records!.length; i++) {
        list_s.add(questions.records![i]);
      }

      print(list_s[0].name);

      return list_s;
    });
  }
}

And At last the UI part Is :

class _FeedbackListPageState extends State<FeedbackListPage> {
 
  List<Records> list_s = [];
  

  @override
  void initState() {
    super.initState();

    FormController().getRecordList().then((value) {
      setState(() {
        list_s = value;
      });
    });

    
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: darkGreen,
        elevation: 0.0,
        titleSpacing: 10.0,
        title: Text(widget.title),
        centerTitle: true,
        leading: InkWell(
          onTap: () {
            Navigator.pop(context);
          },
          child: const Icon(
            Icons.arrow_back_ios,
            color: Colors.black54,
          ),
        ),
      ),
      body: ListView.builder(
        itemCount: list_s.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Row(
              children: <Widget>[
                Icon(Icons.person),
                Expanded(
                  child: Text("${list_s[index].name} (${list_s[index].email})"),
                )
              ],
            ),
            subtitle: Row(
              children: <Widget>[
                Icon(Icons.message),
                Expanded(
                  child: Text(list_s[index].feedback.toString()),
                )
              ],
            ),
          );
        },
      ),
    );
  }
}

Upvotes: 3

Ash
Ash

Reputation: 5712

You can also Do it like

  List<dynamic> parsedListJson = jsonDecode("your json string");
  List<Item> itemsList = List<Item>.from(parsedListJson.map<Item>((dynamic i) => Item.fromJson(i)));

where Item is your custom class, where you implemented toJson and fromJson.

Upvotes: 58

ethicnology
ethicnology

Reputation: 594

Full example

Here a full example of JSON serialization and deserialization for Object, List<Object>. Here we have a Main class which is composed by a nested Sub class and a List<Sub>.

Json sample

{
    "title": "something",
    "sub": {"name": "a", "num": 0},
    "sub_list": [
      {"name": "b", "num": 1},
      {"name": "c", "num": 2}
    ]
}

Main class

class Main {
  String title;
  Sub sub;
  List<Sub> subList;

  Main(this.title, this.sub, this.subList);

  Main.fromJson(Map<String, dynamic> json)
      : title = json['title'],
        sub = Sub.fromJson(json['sub']),
        subList = List<dynamic>.from(json['sub_list'])
            .map((i) => Sub.fromJson(i))
            .toList();

  Map<String, dynamic> toJson() => {
        'title': title,
        'sub': sub.toJson(),
        'sub_list': subList.map((item) => item.toJson()).toList(),
      };
}

Sub class

class Sub {
  String name;
  int n;

  Sub(this.name, this.n);

  Sub.fromJson(Map<String, dynamic> json)
      : name = json['name'],
        n = json['n'];

  Map<String, dynamic> toJson() => {
        'name': name,
        'n': n,
      };
}

usage

void main(List<String> args) {
  var sub = Sub("a", 0);
  print(sub.name); // a

  Map<String, dynamic> jsonSub = {"name": "a", "n": 0};
  var subFromJson = Sub.fromJson(jsonSub);
  print(subFromJson.n); // 0

  var main = Main("something", Sub("a", 0), [Sub("b", 1)]);
  print(main.title); // something
  print(main.sub.name); // a
  print(main.subList[0].name); // b

  var jsonMain = {
    "title": "something",
    "sub": {"name": "a", "n": 0},
    "sub_list": [
      {"name": "b", "n": 1},
      {"name": "c", "n": 2}
    ]
  };
  var mainFromJson = Main.fromJson(jsonMain);
  print(mainFromJson.title); // something
  print(mainFromJson.sub.name); // a
  print(mainFromJson.subList[0].name); // b
  print(mainFromJson.subList[1].name); // c
}

Upvotes: 11

Brett Sutton
Brett Sutton

Reputation: 4554

With strong-mode enabled none of the above solutions will actually compile as type information is missing.

This compiles as of dart 2.14 with strong mode enabled:

analysis_options.yaml


include: package:lints/recommended.yaml

analyzer:
  strong-mode:
    implicit-casts: false
    implicit-dynamic: false

    import 'dart:convert';

    // read the json file. This example use dcli but you just
    // need [source] to contain the json string.
    var source = dcli.read(_failedTrackerFilename).toParagraph();

    var l = json.decode(source) as Iterable;
    var failures = List<UnitTest>.from(l.map<UnitTest>(
          (dynamic i) => UnitTest.fromJson(i as Map<String, dynamic>)));

Upvotes: 5

vinod yadav
vinod yadav

Reputation: 542

Follow these steps:

  1. Create a model class (named as LoginResponse): click here to convert json to dart .

  2. LoginResponce loginResponce=LoginResponce.fromJson(json.decode(response.body));

  3. Now you get your data in instence of model (as loginResponce ).

Upvotes: 4

Fallenreaper
Fallenreaper

Reputation: 10682

Well, your service would handle either the response body being a map, or a list of maps accordingly. Based on the code you have, you are accounting for 1 item.

If the response body is iterable, then you need to parse and walk accordingly, if I am understanding your question correctly.

Example:

Iterable l = json.decode(response.body);
List<Post> posts = List<Post>.from(l.map((model)=> Post.fromJson(model)));

where the post is a LIST of posts.

EDIT: I wanted to add a note of clarity here. The purpose here is that you decode the response returned. The next step, is to turn that iterable of JSON objects into an instance of your object. This is done by creating fromJson methods in your class to properly take JSON and implement it accordingly. Below is a sample implementation.

class Post {
  // Other functions and properties relevant to the class
  // ......
  /// Json is a Map<dynamic,dynamic> if i recall correctly.
  static fromJson(json): Post {
    Post p = new Post()
    p.name = ...
    return p
  }
}

I am a bit abstracted from Dart these days in favor of a better utility for the tasks needing to be accomplished. So my syntax is likely off just a little, but this is Pseudocode.

Upvotes: 197

Anouar khaldi
Anouar khaldi

Reputation: 782

First, create a class that matches your json data, in my case, I create (generate) class named Img:

import 'dart:convert';

Img imgFromJson(String str) => Img.fromJson(json.decode(str));
String imgToJson(Img data) => json.encode(data.toJson());

class Img {
    String id;
    String img;
    dynamic decreption;

    Img({
        this.id,
        this.img,
        this.decreption,
    });

    factory Img.fromJson(Map<String, dynamic> json) => Img(
        id: json["id"],
        img: json["img"],
        decreption: json["decreption"],
    );

    Map<String, dynamic> toJson() => {
        "id": id,
        "img": img,
        "decreption": decreption,
    };
}

PS. You can use app.quicktype.io to generate your json data class in dart. then send your post/get to your server:

Future<List<Img>> _getimages() async {
    var response = await http.get("http://192.168.115.2/flutter/get_images.php");
    var rb = response.body;

    // store json data into list
    var list = json.decode(rb) as List;

    // iterate over the list and map each object in list to Img by calling Img.fromJson
    List<Img> imgs = list.map((i)=>Img.fromJson(i)).toList();

    print(imgs.runtimeType); //returns List<Img>
    print(imgs[0].runtimeType); //returns Img

    return imgs;
}

for more info see Parsing complex JSON in Flutter

Upvotes: 12

Akhil Shukla
Akhil Shukla

Reputation: 501

This is my Model class -

  class SuggestedMovie {
  String title;
  String genres;
  int movieId;
  SuggestedMovie({this.title, this.genres, this.movieId});
  factory SuggestedMovie.fromJson(Map<dynamic, dynamic> parsedJson) {
    return SuggestedMovie(
      movieId: parsedJson['movieId'],
      title: parsedJson['title'] as String,
      genres: parsedJson['genres'] as String,
    );
  }
}

The one below is the code for Deserializing the JSON response into List

 suggestedMovie = (json.decode(jsonResponse.data) as List)
      .map((i) => SuggestedMovie.fromJson(i))
      .toList();

Upvotes: 3

Bilal Şimşek
Bilal Şimşek

Reputation: 5943

I always use this way with no problem;

List<MyModel> myModels;
var response = await http.get("myUrl");

myModels=(json.decode(response.body) as List).map((i) =>
              MyModel.fromJson(i)).toList();

Upvotes: 118

Hammad Tariq
Hammad Tariq

Reputation: 13441

Just another example on JSON Parsing for further clarification.

Let say we want to parse items array in our JSON Object.

factory YoutubeResponse.fromJSON(Map<String, dynamic> YoutubeResponseJson) 
 {

// Below 2 line code is parsing JSON Array of items in our JSON Object (YouttubeResponse)


var list = YoutubeResponseJson['items'] as List;
List<Item> itemsList = list.map((i) => Item.fromJSON(i)).toList();

return new YoutubeResponse(
    kind: YoutubeResponseJson['kind'],
    etag: YoutubeResponseJson['etag'],
    nextPageToken: YoutubeResponseJson['nextPageToken'],
    regionCode: YoutubeResponseJson['regionCode'],
    mPageInfo: pageInfo.fromJSON(YoutubeResponseJson['pageInfo']),

    // Here we are returning parsed JSON Array.

    items: itemsList);

  }

Upvotes: 22

Related Questions