can't receive the array to model - arrays

I'm receiving the following array to a flutter app through a model.
[
{
"shopid": "5e898e320328500017c589dd",
"shopname": "f",
"refID": "5e4e33e512e82b0017da6c04",
"refName": "test",
"_id": "5e8f3a6c5936e90017e294c8",
"saledata": [
{
"_id": "5e8f3a6c5936e90017e294c9",
"brand": "bdgbf",
"model": "gbgvffgf",
"capacity": "11gb",
"imei": "84788585",
"price": "414141"
}
],
"total": "414141",
"saletime": "2020-04-09T20:40:31.212Z",
"__v": 0
}
]
I can retrieve everything except saledata to the following modal. And that works fine.
The problem is getting the saledata I want retrieve that array too.
class SaleItem {
String shopID;
String saleID;
String total;
String shopname;
String saletime;
String refid;
String refname;
SaleItem(
{this.shopID,
this.saleID,
this.total,
this.shopname,
this.saletime,
this.refid,
this.refname,
});
factory SaleItem.fromJson(Map<String, dynamic> json) {
return SaleItem(
shopID: json["shopid"] as String,
saleID: json["_id"] as String,
total: json["total"] as String,
shopname: json["shopname"] as String,
saletime: json["saletime"] as String,
refid: json["refID"] as String,
refname: json["refName"] as String,
);
}
}
I tried to get this as Object but it did not work. How can I receive this saledata to my modal ?

class SaleItem {
String shopID;
String saleID;
String total;
String shopname;
String saletime;
String refid;
String refname;
List<SaleData> saleData;
SaleItem(
{this.shopID,
this.saleID,
this.total,
this.shopname,
this.saletime,
this.refid,
this.refname,
this.saleData
});
factory SaleItem.fromJson(Map<String, dynamic> json) {
return SaleItem(
shopID: json["shopid"] as String,
saleID: json["_id"] as String,
total: json["total"] as String,
shopname: json["shopname"] as String,
saletime: json["saletime"] as String,
refid: json["refID"] as String,
refname: json["refName"] as String,
saleData: (json['saledata'] as List)
?.map((i) => SaleData.fromJson(i))
?.toList(),
);
}
}
class SaleData {
String sId;
String brand;
String model;
String capacity;
String imei;
String price;
SaleData(
{this.sId, this.brand, this.model, this.capacity, this.imei, this.price});
SaleData.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
brand = json['brand'];
model = json['model'];
capacity = json['capacity'];
imei = json['imei'];
price = json['price'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['_id'] = this.sId;
data['brand'] = this.brand;
data['model'] = this.model;
data['capacity'] = this.capacity;
data['imei'] = this.imei;
data['price'] = this.price;
return data;
}
}

Related

How to model data of a multidimensional array with different hierarchy

I am working with an expansion tile in a flutter that shows user information in an irregular hierarchical order.
I am optimizing the code to increase the performance of the expansion tile widget. Unit-III hierarchy differs from the rest and I am having a difficult time creating data classes from it. Any reference to dealing with multidimensional arrays effectively will be very helpful.
JSON:
{
"status": true,
"message": "",
"data": {
"1. UNIT-I CALCULUS": {
"1.1 Limit and Continuity": {
"is_lesson": true,
"lesson_detail": [
{
"title": "Eg 1",
"lesson_id": "34670",
"course_id": "126",
"section_id": "2145",
"duration": "00:01:08",
"is_lesson_free": "0",
"video_url": "https://lb.mero.school/api/v1/video/retrieve_path/7f1814c2-bc5a-48b7-9b5a-4e493f564a03",
"video_type": "bulk_videos",
"attachment_type": "url",
"attachment": null
}
],
"2. UNIT-II ALGEBRA": {
"2.1 Complex Numbers": {
"is_lesson": true,
"lesson_detail": [
{
"title": "Eg 1",
"lesson_id": "37069",
"course_id": "126",
"section_id": "2145",
"duration": "00:02:32",
"is_lesson_free": "0",
"video_url": "https://lb.mero.school/api/v1/video/retrieve_path/d42d03a3-c857-4e99-8439-edbda003d296",
"video_type": "bulk_videos",
"attachment_type": "url",
"attachment": null
}
]
}
},
"3. UNIT-III VECTOR ALGEBRA": {
"is_lesson": true,
"lesson_detail": [
{
"title": "Q. 1",
"lesson_id": "33898",
"course_id": "126",
"section_id": "2145",
"duration": "00:02:42",
"is_lesson_free": "0",
"video_url": "https://lb.mero.school/api/v1/video/retrieve_path/5c6487a2-a3df-4175-b20c-57134d2684dd",
"video_type": "bulk_videos",
"attachment_type": "url",
"attachment": null
}
]
}
}
}
}
}
Data class:
import 'dart:convert';
import 'package:flutter/foundation.dart';
SectionDemoData sectionDemoDataFromMap(String str) =>
SectionDemoData.fromMap(json.decode(str));
String sectionDemoDataToMap(SectionDemoData data) => json.encode(data.toMap());
class SectionDemoData {
SectionDemoData({
required this.status,
required this.message,
required this.data,
});
final bool status;
final String message;
final SubSection data;
factory SectionDemoData.fromMap(Map<String, dynamic> json) => SectionDemoData(
status: json["status"],
message: json["message"],
data: SubSection.fromMap(json["data"]),
);
Map<String, dynamic> toMap() => {
"status": status,
"message": message,
"data": data.toMap(),
};
}
class SubSection {
SubSection({
required this.lessonList,
required this.lessonName,
isLessonItself = false,
});
final List<Lesson> lessonList;
final List<String> lessonName;
bool isLessonItself = false;
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'lessonList': lessonList.map((x) => x.toMap()).toList()});
return result;
}
factory SubSection.fromMap(Map<String, dynamic> map) {
map.forEach(
(key, value) {
if (isLessonItself) print("KEY HERR:" + value);
},
);
return SubSection(
lessonName: List<String>.from(map => map.Key),
lessonList:
List.generate(map.keys.length, (index) => Lesson.fromMap(map[index])),
);
}
String toJson() => json.encode(toMap());
factory SubSection.fromJson(String source) =>
SubSection.fromMap(json.decode(source));
#override
String toString() => 'SubSection(lesson: ,lessonList: $lessonList)';
}
class Lesson {
Lesson({
required this.isLesson,
required this.lessonDetailList,
});
final bool isLesson;
final List<LessonDetail> lessonDetailList;
factory Lesson.fromMap(Map<String, dynamic> json) => Lesson(
isLesson: json["is_lesson"],
lessonDetailList: List<LessonDetail>.from(
json["lesson_detail"].map((x) => LessonDetail.fromMap(x))),
);
Map<String, dynamic> toMap() => {
"is_lesson": isLesson,
"lesson_detail":
List<dynamic>.from(lessonDetailList.map((x) => x.toMap())),
};
}
class LessonDetail {
LessonDetail({
required this.title,
required this.lessonId,
required this.courseId,
required this.sectionId,
required this.duration,
required this.isLessonFree,
required this.videoUrl,
required this.videoType,
required this.attachmentType,
required this.attachment,
});
final String title;
final String lessonId;
final String courseId;
final String sectionId;
final String duration;
final String isLessonFree;
final String videoUrl;
final String videoType;
final String attachmentType;
final dynamic attachment;
factory LessonDetail.fromMap(Map<String, dynamic> json) => LessonDetail(
title: json["title"],
lessonId: json["lesson_id"],
courseId: json["course_id"],
sectionId: json["section_id"],
duration: json["duration"],
isLessonFree: json["is_lesson_free"],
videoUrl: json["video_url"],
videoType: json["video_type"],
attachmentType: json["attachment_type"],
attachment: json["attachment"],
);
Map<String, dynamic> toMap() => {
"title": title,
"lesson_id": lessonId,
"course_id": courseId,
"section_id": sectionId,
"duration": duration,
"is_lesson_free": isLessonFree,
"video_url": videoUrl,
"video_type": videoType,
"attachment_type": attachmentType,
"attachment": attachment,
};
}
I think I found the working around it. Making use of keys and values of the given Map object did the trick. Any optimization on this is highly appreciated.
Code:
import 'dart:convert';
SectionDemoData sectionDemoDataFromMap(String str) =>
SectionDemoData.fromMap(json.decode(str));
String sectionDemoDataToMap(SectionDemoData data) => json.encode(data.toMap());
class SectionDemoData {
SectionDemoData({
required this.status,
required this.message,
required this.data,
});
final bool status;
final String message;
final SubSection data;
factory SectionDemoData.fromMap(Map<String, dynamic> json) => SectionDemoData(
status: json["status"],
message: json["message"],
data: SubSection.fromMap(json["data"]),
);
Map<String, dynamic> toMap() => {
"status": status,
"message": message,
"data": data.toMap(),
};
}
class SubSection {
SubSection({
required this.lessonList,
required this.lessonName,
});
final List<Lesson> lessonList;
final List<String> lessonName;
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'lessonList': lessonList.map((x) => x.toMap()).toList()});
return result;
}
factory SubSection.fromMap(Map<String, dynamic> map) {
return SubSection(
lessonName: List.from(map["data"].keys), //Modified Code
lessonList:
List<Lesson>.from(map["data"].values.map((x) => Lesson.fromMap(x))), //Modified Code
);
}
String toJson() => json.encode(toMap());
factory SubSection.fromJson(String source) =>
SubSection.fromMap(json.decode(source));
#override
String toString() =>
'SubSection(lesson: $lessonName,lessonList: ${lessonList.toString()})';
}
class Lesson {
Lesson({
required this.isLesson,
required this.lessonDetailList,
});
final bool isLesson;
final List<LessonDetail> lessonDetailList;
factory Lesson.fromMap(Map<String, dynamic> json) => Lesson(
isLesson: json["is_lesson"],
lessonDetailList: List<LessonDetail>.from(
json["lesson_detail"].map((x) => LessonDetail.fromMap(x))),
);
Map<String, dynamic> toMap() => {
"is_lesson": isLesson,
"lesson_detail":
List<dynamic>.from(lessonDetailList.map((x) => x.toMap())),
};
}
class LessonDetail {
LessonDetail({
required this.title,
required this.lessonId,
required this.courseId,
required this.sectionId,
required this.duration,
required this.isLessonFree,
required this.videoUrl,
required this.videoType,
required this.attachmentType,
required this.attachment,
});
final String title;
final String lessonId;
final String courseId;
final String sectionId;
final String duration;
final String isLessonFree;
final String videoUrl;
final String videoType;
final String attachmentType;
final dynamic attachment;
factory LessonDetail.fromMap(Map<String, dynamic> json) => LessonDetail(
title: json["title"],
lessonId: json["lesson_id"],
courseId: json["course_id"],
sectionId: json["section_id"],
duration: json["duration"],
isLessonFree: json["is_lesson_free"],
videoUrl: json["video_url"],
videoType: json["video_type"],
attachmentType: json["attachment_type"],
attachment: json["attachment"],
);
Map<String, dynamic> toMap() => {
"title": title,
"lesson_id": lessonId,
"course_id": courseId,
"section_id": sectionId,
"duration": duration,
"is_lesson_free": isLessonFree,
"video_url": videoUrl,
"video_type": videoType,
"attachment_type": attachmentType,
"attachment": attachment,
};
}

Multidimensional ArrayList in flutter convert to model class

I am using WordPress Api's for my flutter application.
I have model class(POJO) in which there is ArrayList inside another arrayList.I don't know how to convert it to model class. Please Help.
The Json is:
wp:term: [
[
{
id: 22,
link: "https://example.com/category/ut/xyz/",
name: "XYZ",
slug: "xyx",
taxonomy: "category",
}
],
]
Maybe you meant it:
class Obj {
Obj({
this.wpTerm,
});
final List<List<WpTerm>> wpTerm;
factory Obj.fromJson(Map<String, dynamic> json) => Obj(
wpTerm: List<List<WpTerm>>.from(json["wp:term"].map((x) => List<WpTerm>.from(x.map((x) => WpTerm.fromJson(x))))),
);
Map<String, dynamic> toJson() => {
"wp:term": List<dynamic>.from(wpTerm.map((x) => List<dynamic>.from(x.map((x) => x.toJson())))),
};
}
class WpTerm {
WpTerm({
this.id,
this.link,
this.name,
this.slug,
this.taxonomy,
});
final int id;
final String link;
final String name;
final String slug;
final String taxonomy;
factory WpTerm.fromJson(Map<String, dynamic> json) => WpTerm(
id: json["id"],
link: json["link"],
name: json["name"],
slug: json["slug"],
taxonomy: json["taxonomy"],
);
Map<String, dynamic> toJson() => {
"id": id,
"link": link,
"name": name,
"slug": slug,
"taxonomy": taxonomy,
};
}
//https://app.quicktype.io/

Trouble with JSON Parsing in Swift

Having a slight trouble in saving my decoded JSON data into the struct, not sure what I'm doing wrong here.
What I'm trying to do is call the sneaker database and retrieve the results and display them in a view, i can see the JSON call is working with the print but now stuck on how to get this in a way I can display it into a view.
JSON
{
"count": 1,
"results": [
{
"id": "029ddc1d-a64b-469b-b9df-bd21c84a608e",
"brand": "Jordan",
"colorway": "Deep Ocean/Sail-Cement Grey-Fire Red",
"gender": "men",
"name": "SE Sashiko",
"releaseDate": "2020-12-05",
"retailPrice": 190,
"shoe": "Jordan 4 Retro",
"styleId": "CW0898-400",
"title": "Jordan 4 Retro SE Sashiko",
"year": 2020,
"media": {
"imageUrl": "https://images.stockx.com/images/Air-Jordan-4-Retro-SE-Deep-Ocean-Product.jpg?fit=fill&bg=FFFFFF&w=700&h=500&auto=format,compress&trim=color&q=90&dpr=2&updated_at=1609439370",
"smallImageUrl": "https://images.stockx.com/images/Air-Jordan-4-Retro-SE-Deep-Ocean-Product.jpg?fit=fill&bg=FFFFFF&w=300&h=214&auto=format,compress&trim=color&q=90&dpr=2&updated_at=1609439370",
"thumbUrl": "https://images.stockx.com/images/Air-Jordan-4-Retro-SE-Deep-Ocean-Product.jpg?fit=fill&bg=FFFFFF&w=140&h=100&auto=format,compress&trim=color&q=90&dpr=2&updated_at=1609439370"
}
}
]
}
Model:
struct APIResponse: Decodable {
enum CodingKeys: String, CodingKey {
case shoeResults = "results"
}
let shoeResults: [Shoe]
}
struct Shoe: Decodable {
public var id: String
public var brand: String
public var colorway: String
public var gender: String
public var name: String
public var releaseDate: String
public var retailPrice: Int
public var shoe: String
public var styleId: String
public var title: String
public var year: Int
public var media: mediaData
enum CodingKeys: String, CodingKey {
case id = "id"
case brand = "brand"
case colorway = "colorway"
case gender = "gender"
case name = "name"
case releaseDate = "releaseDate"
case retailPrice = "retailPrice"
case shoe = "shoe"
case styleId = "styleId"
case title = "title"
case year = "year"
case media = "media"
}
}
struct mediaData: Decodable {
var imageUrl: String
var smallImageUrl: String
var thumbUrl: String
}
Shoefetcher class:
public class ShoeFetcher: ObservableObject {
init(){
load()
}
func load() {
let url = URL(string: "https://api.thesneakerdatabase.com/v1/sneakers?limit=10&styleId=cw0898-400")!
URLSession.shared.dataTask(with: url) {(data,response,error) in
do {
if let d = data {
let decodedLists = try JSONDecoder().decode(APIResponse.self, from: d)
DispatchQueue.main.async {
print(decodedLists)
}
}else {
print("No Data")
}
}catch DecodingError.keyNotFound(let key, let context) {
Swift.print("could not find key \(key) in JSON: \(context.debugDescription)")
} catch DecodingError.valueNotFound(let type, let context) {
Swift.print("could not find type \(type) in JSON: \(context.debugDescription)")
} catch DecodingError.typeMismatch(let type, let context) {
Swift.print("type mismatch for type \(type) in JSON: \(context.debugDescription)")
} catch DecodingError.dataCorrupted(let context) {
Swift.print("data found to be corrupted in JSON: \(context.debugDescription)")
} catch let error as NSError {
NSLog("Error in read(from:ofType:) domain= \(error.domain), description= \(error.localizedDescription)")
}
}.resume()
}
}
output of decodedlists:
APIResponse(shoeResults: [Sneakers.Shoe(id: "029ddc1d-a64b-469b-b9df-bd21c84a608e", brand: "Jordan", colorway: "Deep Ocean/Sail-Cement Grey-Fire Red", gender: "men", name: "SE Sashiko", releaseDate: "2020-12-05", retailPrice: 190, shoe: "Jordan 4 Retro", styleId: "CW0898-400", title: "Jordan 4 Retro SE Sashiko", year: 2020, media: SneakerNews.mediaData(imageUrl: "https://images.stockx.com/images/Air-Jordan-4-Retro-SE-Deep-Ocean-Product.jpg?fit=fill&bg=FFFFFF&w=700&h=500&auto=format,compress&trim=color&q=90&dpr=2&updated_at=1609439370", smallImageUrl: "https://images.stockx.com/images/Air-Jordan-4-Retro-SE-Deep-Ocean-Product.jpg?fit=fill&bg=FFFFFF&w=300&h=214&auto=format,compress&trim=color&q=90&dpr=2&updated_at=1609439370", thumbUrl: "https://images.stockx.com/images/Air-Jordan-4-Retro-SE-Deep-Ocean-Product.jpg?fit=fill&bg=FFFFFF&w=140&h=100&auto=format,compress&trim=color&q=90&dpr=2&updated_at=1609439370"))])
Edit:
updated the shoefetcher class:
public class ShoeFetcher: ObservableObject {
#Published var shoeResults: [Shoe] = [] //added
init(){
load()
}
func load() {
let url = URL(string: "https://api.thesneakerdatabase.com/v1/sneakers?limit=10&styleId=cw0898-400")!
URLSession.shared.dataTask(with: url) {(data,response,error) in
do {
if let d = data {
let decodedLists = try JSONDecoder().decode(APIResponse.self, from: d)
DispatchQueue.main.async {
self.shoeResults = decodedLists.shoeResults //added
print(self.shoeResults)
}
}else {
print("No Data")
}
}catch DecodingError.keyNotFound(let key, let context) {
Swift.print("could not find key \(key) in JSON: \(context.debugDescription)")
} catch DecodingError.valueNotFound(let type, let context) {
Swift.print("could not find type \(type) in JSON: \(context.debugDescription)")
} catch DecodingError.typeMismatch(let type, let context) {
Swift.print("type mismatch for type \(type) in JSON: \(context.debugDescription)")
} catch DecodingError.dataCorrupted(let context) {
Swift.print("data found to be corrupted in JSON: \(context.debugDescription)")
} catch let error as NSError {
NSLog("Error in read(from:ofType:) domain= \(error.domain), description= \(error.localizedDescription)")
}
}.resume()
}
}
added a ContentView to just see if I can display something off the JSON file.
struct ContentView: View {
#ObservedObject var fetcher = ShoeFetcher()
#State var Shoes: Shoe
var body: some View {
VStack {
Text("Shoes")
Text(Shoes.brand)
}
}
}
errors I'm getting is Missing argument for a parameter 'Shoes' in call in my SneakersApp.swift file
import SwiftUI
#main
struct SneakersApp: App {
var body: some Scene {
WindowGroup {
ContentView() //error here
}
}
}
I have a feeling I need to initialise the JSON variables but cant seem to workout where/how I do that
You've done all of the hard work of getting the data from the API and decoding it into structs.
To display it in a view, you could do something like this:
struct ContentView : View {
#StateObject var fetcher = ShoeFetcher()
var body: some View {
VStack {
if let response = fetcher.apiResponse {
ForEach(response.shoeResults, id: \.id) { shoe in
Text(shoe.name)
Text(shoe.brand)
Text(shoe.title)
Text("\(shoe.year)")
Text("\(shoe.retailPrice)")
}
}
}
}
}
Your current API call is only returning one Shoe in the array, so the ForEach call isn't doing much, but it would certainly be important if you had more results.

_TypeError (type 'List' is not a subtype of type 'Map') flutter

I did a similar post here : problem but i did the same and i have always the problem...
I have my class :
class PollQuestionsDto {
int id;
String entitled;
int difficulty;
List<Answer> answers;
PollQuestionsDto({this.id, this.entitled, this.difficulty, this.answers});
PollQuestionsDto.fromJson(Map<String, dynamic> json) {
id = json['id'];
entitled = json['entitled'];
difficulty = json['difficulty'];
if (json['answers'] != null) {
answers = new List<Answer>();
json['answers'].forEach((v) {
answers.add(new Answer.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['entitled'] = this.entitled;
data['difficulty'] = this.difficulty;
if (this.answers != null) {
data['answers'] = this.answers.map((v) => v.toJson()).toList();
}
return data;
}
}
Method for ask API :
Future<List<PollQuestionsDto>> getPollQuestions() async {
String url = 'http://10.0.2.2:3000/v1/api/poll/40/question?page=0';
//String url = 'http://10.0.2.2:3000/v1/api/poll/$idPoll/question?page=0';
String token = await Candidate().getToken();
final response = await http.get(url, headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
});
if (response.statusCode == 200) {
print(jsonDecode(response.body));
/*List pollsList = jsonDecode(response.body) ;
List<PollQuestionsDto> polls = [];
for (var themeMap in pollsList) {
polls.add(PollQuestionsDto.fromJson(themeMap));
}
print(polls);
print('Get Poll ${response.body}');*/
} else {
throw Exception('Failed get poll questions');
}
}
when i ask my API, the result of request is :
{results: [{id: 2, entitled: Le langage utilisé sous Flutter est le dart ?, difficulty: 1, answers: [{id: 9, entitled: Oui, isCorrect: true}, {id: 10, entitled: Non, isCorrect: false}]}], pageCount: 3, next: http://localhost:3000/v1/api/poll/40/question?page=1, previous: }
When i want make the result in the list i have the same error :
_TypeError (type 'List' is not a subtype of type 'Map')
Why ?
If the result is
{
"results": [
{
"id": 2,
"entitled": "Le langage utilisé sous Flutter est le dart ?",
"difficulty": 1,
"answers": [
{
"id": 9,
"entitled": "Oui",
"isCorrect": true
},
{
"id": 10,
"entitled": "Non",
"isCorrect": false
}
]
}
],
"pageCount": 3,
"next": "http://localhost:3000/v1/api/poll/40/question?page=1"
}
you need to add ['results'] like this:
List pollsList = jsonDecode(jsonstr)['results'];
You need to cast json['answers'] to List like
if (json['answers'] != null) {
answers = (json['answers'] as List).map((v) => Answer.fromJson(v)).toList();
}
Its better to use https://pub.dev/packages/json_annotation instead of implementing toJson and fromJson by hand unless you have special requirement.
I am able to parse following string
[
{
"id": 1,
"entitled": "yes",
"difficulty": 1,
"answers": [
{
"value":"a"
}
]
}
]
using
class PollQuestionsDto {
int id;
String entitled;
int difficulty;
List<Answer> answers;
PollQuestionsDto({this.id, this.entitled, this.difficulty, this.answers});
PollQuestionsDto.fromJson(Map<String, dynamic> json) {
id = json['id'];
entitled = json['entitled'];
difficulty = json['difficulty'];
if (json['answers'] != null) {
answers = new List<Answer>();
json['answers'].forEach((v) {
answers.add(new Answer.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['entitled'] = this.entitled;
data['difficulty'] = this.difficulty;
if (this.answers != null) {
data['answers'] = this.answers.map((v) => v.toJson()).toList();
}
return data;
}
#override String toString() => toJson().toString();
static List<PollQuestionsDto> arrayOfQuestionsFromJson(String json) {
return (jsonDecode(json) as List).map((e) => PollQuestionsDto.fromJson(e)).toList();
}
}
Is this what you are expecting (Your might have to change json for Answer as I used Anser class with one variable value)??

Flutter - Sembast Database insert List of Objects

I'm about to use the database "Sembast" in Flutter.
Simple objects with data types like string and int are working properly. However, it becomes problematic when using Lists.
I have created an example and oriented myself on the following tutorial: https://resocoder.com/2019/04/06/flutter-nosql-database-sembast-tutorial-w-bloc/
In my example, there are fruits and leaves as objects. A fruit contains a list of leaves.
class Fruit {
final String id;
final String name;
final bool isSweet;
final List<Leaves> leaves;
...
}
class Leaves {
final String id;
final String name;
...
}
//Create a sample object
var leaveOne = Leaves(id: "1", name: "leaveOne");
var leaveTwo = Leaves(id: "2", name: "leaveTwo");
var leaveThree = Leaves(id: "3", name: "leaveThree");
var leavesList = List<Leaves>();
leavesList.add(leaveOne);
leavesList.add(leaveTwo);
leavesList.add(leaveThree);
var fruit = Fruit(id: "1", name: "Apple", isSweet: true, leaves: leavesList);
_fruitDao.insert(fruit);
// The fruitDao.insert makes following
Future insert(Fruit fruit) async {
await _fruitStore.add(await _db, fruit.toJson());
}
The JSON looks like that: {id: 1, name: Apple, isSweet: true, leaves: [Instance of 'Leaves', Instance of 'Leaves', Instance of 'Leaves']}
The ERROR is following:
[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Invalid argument(s): value Instance of 'Leaves' unsupported type Leaves
As pointed at, Instance of 'Leaves' is not a valid type so each Leave must be converted as well. Hard to guess what you are doing without seeing your toJson() but something like this should work (could be largely optimized):
class Fruit {
final String id;
final String name;
final bool isSweet;
final List<Leaves> leaves;
Fruit({this.id, this.name, this.isSweet, this.leaves});
Map<String, dynamic> toJson() => <String, dynamic>{
'id': id,
'name': name,
'isSweet': isSweet,
'leaves': leaves?.map((leave) => leave.toJson())?.toList(growable: false)
};
}
class Leaves {
final String id;
final String name;
Leaves({this.id, this.name});
Map<String, dynamic> toJson() => <String, dynamic>{'id': id, 'name': name};
}
and your json should look like something this this:
{
"id": "1",
"name": "Apple",
"isSweet": true,
"leaves": [
{
"id": "1",
"name": "leaveOne"
},
{
"id": "2",
"name": "leaveTwo"
},
{
"id": "3",
"name": "leaveThree"
}
]
}
Here is an example in addition to #alextk answer with converting to and from without any code generation or library's.
class Fruit {
final String id;
final String name;
final bool isSweet;
final List<Leaves> leaves;
Fruit({this.id, this.name, this.isSweet, this.leaves});
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'isSweet': isSweet,
'leaves': leaves.map((leave) => leave.toMap()).toList(growable: false)
};
}
static Fruit fromMap(Map<String, dynamic> map) {
return Fruit(
id: map['id'],
name: map['name'],
isSweet: map['isSweet'],
leaves: map['leaves'].map((mapping) => Leaves.fromMap(mapping)).toList().cast<Leaves>(),
);
}
}
class Leaves {
final String id;
final String name;
Leaves({this.id, this.name});
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
};
}
static Leaves fromMap(Map<String, dynamic> map) {
return Leaves(
id: map['id'],
name: map['name'],
);
}
}
For cases when you use freezed, I found this solution:
...
...
#freezed
class Fruit with _$Fruit {
//add this line
#JsonSerializable(explicitToJson: true)
const factory Fruit({...}) = _Fruit;
factory Fruit.fromJson(Map<String, dynamic> json) => _$FruitFromJson(json);
}

Resources