JC18
JC18

Reputation: 65

Flutter: complex json serialization. Parsing json string to provide into UI

Here is the json string that I get by http request. The aim is to display subjects according to the current weekday.

{
    "first_name": "First Name",
    "batch_name": "Batch 1",
    "enrolled_subjects": [
        "Subject 4",
        "Subject 5"
    ],
    "batch_timetable": {
        "Mon": {
            "Subject 4": [
                "6:00 PM - 7:00 PM"
            ],
            "Subject 5": [
                "5:00 PM - 6:00 PM",
                "7:00 PM - 8:00 PM"
            ],
            "Subject 6": [
                "8:00 PM - 9:00 PM"
            ]
        },
        "Tue": {
            "Subject 4": [
                "6:00 PM - 7:00 PM"
            ],
            "Subject 5": [
                "7:00 PM - 8:00 PM"
            ],
            "Subject 6": [
                "8:00 PM - 9:00 PM"
            ]
        }, ...so on upto "Sun"
    }
}

How to set Model Class for this json string?

I tried this Model Class but it gives this error : type '_InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'Map<String, List<dynamic>>'

I also tried Model Class by quicktype, but I think that won't work in this case.

class HomePageModel {
  HomePageModel({
    this.firstName,
    this.batchName,
    this.subjects,
    this.timetable,
  });

  String firstName;
  String batchName;
  List<String> subjects;
  Map timetable;

  factory HomePageModel.fromJson(Map<String, dynamic> json) => HomePageModel(
        firstName: json["first_name"],
        batchName: json["batch_name"],
        subjects: List<String>.from(json["subjects"].map((x) => x)),
        timetable: Map.from(json["timetable"])
            .map((key, value) => MapEntry(key, value)),
      );

  Map<String, dynamic> toJson() => {
        "first_name": firstName,
        "batch_name": batchName,
        "subjects": List<dynamic>.from(subjects.map((x) => x)),
        "timetable":
            Map.from(timetable.map((key, value) => MapEntry(key, value))),
      };
}

I am using FutureBuilder to display this data into UI. Any help would be appreciated.

Upvotes: 3

Views: 441

Answers (3)

Sagar Acharya
Sagar Acharya

Reputation: 3777

So Far from the json you provided I have created and example for you in the listview format just check it out.

following is the json you provided:

{
    "first_name": "First Name",
    "batch_name": "Batch 1",
    "enrolled_subjects": [
        "Subject 4",
        "Subject 5"
    ],
    "batch_timetable": {
        "Mon": {
            "Subject 4": [
                "6:00 PM - 7:00 PM"
            ],
            "Subject 5": [
                "5:00 PM - 6:00 PM",
                "7:00 PM - 8:00 PM"
            ],
            "Subject 6": [
                "8:00 PM - 9:00 PM"
            ]
        },
        "Tue": {
            "Subject 4": [
                "6:00 PM - 7:00 PM"
            ],
            "Subject 5": [
                "7:00 PM - 8:00 PM"
            ],
            "Subject 6": [
                "8:00 PM - 9:00 PM"
            ]
        }
    }
}

Based on the json I have created a ui

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  bool _isLoading = false;
  List<Timings> timingsList = List();

  Future<String> loadFromAssets() async {
    return await rootBundle.loadString('json/parse.json');
  }

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

  dataLoadFunction() async {
    setState(() {
      _isLoading = true;
    });
    String jsonString = await loadFromAssets();
    Map newStringMap = json.decode(jsonString);
    //print(newStringMap['batch_timetable']);

    newStringMap['batch_timetable'].forEach((key, value) {
      List<Subjects> subjectsList = List();

      print(key);

      // print(value);
      value.forEach((key, value) {
        print(key);
        print(value);
        List<dynamic> timingValue = List();
        timingValue.add(value);
        Subjects subjects = Subjects(subjectName: key, timings: timingValue);
        subjectsList.add(subjects);
      });

      Timings sampleObject = Timings(
        day: key,
        subjectList: subjectsList,
      );
      timingsList.add(sampleObject);
    });
    print(timingsList.length);


    setState(() {
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: _isLoading
            ? CircularProgressIndicator()
            : ListView.builder(
                itemCount: timingsList.length,
                shrinkWrap: true,
                itemBuilder: (BuildContext context, int index) {
                  return Card(
                    child: Column(
                      children: <Widget>[
                        Padding(
                          padding: const EdgeInsets.only(top:10,left:15),
                          child: Row(
                            children: <Widget>[
                              Text('Day :'),
                              Text(timingsList[index].day),
                            ],
                          ),
                        ),
                        Divider(color: Colors.grey,),
                        Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: <Widget>[
                            Text(' Day wise Subjects are :'),
                            ListView.builder(
                              itemCount: timingsList[index].subjectList.length,
                              shrinkWrap: true,
                              itemBuilder: (BuildContext context, int i) {
                                return Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: <Widget>[
                                    Text(timingsList[index]
                                        .subjectList[i]
                                        .subjectName),
                                    for (int j = 0;
                                        j <
                                            timingsList[index]
                                                .subjectList[i]
                                                .timings
                                                .length;
                                        j++)
                                      Text(timingsList[index]
                                          .subjectList[i]
                                          .timings[j]
                                          .toString()),
                                  ],
                                );
                              },
                            )
                          ],
                        )
                      ],
                    ),
                  );
                },
              ),
      ),
    );
  }
}

class Timings {
  final String day;
  final List<Subjects> subjectList;

  Timings({
    this.day,
    this.subjectList,
  });
}

class Subjects {
  final String subjectName;
  final List<dynamic> timings;

  Subjects({this.subjectName, this.timings});
}

I have just added the data, you can decorate it based on your desired ui:

What have I achieved in this code

1) Data will be fetched dynamically so that even if the json changes it will adapt accordingly.

2) Added it in the list view format ,you can do as you want.

Provided the sample ui that I have made enter image description here

Let Me know if it works.

Upvotes: 2

Mostafa Efafi
Mostafa Efafi

Reputation: 795

for rest method :

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

Future<HomePageModel> restSample() async {
  var response = await http.get('your URL');
  var jsonResponse = json.decode(response.body);
  HomePageModel homePageModel = HomePageModel.fromJson(jsonResponse);
  return homePageModel;
}

for call timetable parameters:

homePageModel.batchTimetable.mon;

Upvotes: 0

Mostafa Efafi
Mostafa Efafi

Reputation: 795

use this:

class HomePageModel {
  String firstName;
  String batchName;
  List<String> enrolledSubjects;
  BatchTimetable batchTimetable;

  HomePageModel(
      {this.firstName,
      this.batchName,
      this.enrolledSubjects,
      this.batchTimetable});

  HomePageModel.fromJson(Map<String, dynamic> json) {
    firstName = json['first_name'];
    batchName = json['batch_name'];
    enrolledSubjects = json['enrolled_subjects'].cast<String>();
    batchTimetable = json['batch_timetable'] != null
        ? new BatchTimetable.fromJson(json['batch_timetable'])
        : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['first_name'] = this.firstName;
    data['batch_name'] = this.batchName;
    data['enrolled_subjects'] = this.enrolledSubjects;
    if (this.batchTimetable != null) {
      data['batch_timetable'] = this.batchTimetable.toJson();
    }
    return data;
  }
}

class BatchTimetable {
  Mon mon;
  Mon tue;

  BatchTimetable({this.mon, this.tue});

  BatchTimetable.fromJson(Map<String, dynamic> json) {
    mon = json['Mon'] != null ? new Mon.fromJson(json['Mon']) : null;
    tue = json['Tue'] != null ? new Mon.fromJson(json['Tue']) : null;
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.mon != null) {
      data['Mon'] = this.mon.toJson();
    }
    if (this.tue != null) {
      data['Tue'] = this.tue.toJson();
    }
    return data;
  }
}

class Mon {
  List<String> subject4;
  List<String> subject5;
  List<String> subject6;

  Mon({this.subject4, this.subject5, this.subject6});

  Mon.fromJson(Map<String, dynamic> json) {
    subject4 = json['Subject 4'].cast<String>();
    subject5 = json['Subject 5'].cast<String>();
    subject6 = json['Subject 6'].cast<String>();
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['Subject 4'] = this.subject4;
    data['Subject 5'] = this.subject5;
    data['Subject 6'] = this.subject6;
    return data;
  }
}

Upvotes: 0

Related Questions