How to model data of a multidimensional array with different hierarchy - arrays

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,
};
}

Related

A value of type 'Future<QuerySnapshot<Map<String, dynamic>>>' can't be assigned to a variable of type 'QuerySnapshot<Object?>'

I'm creating a social media type-app and this function creates a post publicly for everyone on the app to see
static void createPost(Post post) {
postsRef.doc(post.authorId).set({'postTime': post.timestamp});
postsRef.doc(post.authorId).collection("userPosts").add({
"text": post.text,
"image": post.image,
"authorId": post.authorId,
"timestamp": post.timestamp,
"likes": post.likes
}).then((doc) {
QuerySnapshot homeSnapshot =
usersRef.doc(post.authorId).collection('users').get();
for (var docSnapshot in homeSnapshot.docs) {
feedRefs.doc(docSnapshot.id).collection('userFeed').doc(doc.id).set({
"text": post.text,
"image": post.image,
"authorId": post.authorId,
"timestamp": post.timestamp,
"likes": post.likes
});
}
});
}
the error part of this is the
QuerySnapshot homeSnapshot =
usersRef.doc(post.authorId).collection('users').get();
then also the Post model being passed in the function if needed:
import 'package:cloud_firestore/cloud_firestore.dart';
class Post {
String id;
String authorId;
String text;
String image;
Timestamp timestamp;
int likes;
Post({
required this.id,
required this.authorId,
required this.text,
required this.image,
required this.timestamp,
required this.likes,
});
factory Post.fromDoc(DocumentSnapshot doc) {
return Post(
id: doc.id,
authorId: doc['authorId'],
text: doc['text'],
image: doc['image'],
timestamp: doc['timestamp'],
likes: doc['likes'],
);
}
}
then obviously the error is in the title, any help is much appreciated, thank you :D
You should await for async function. So change this:
QuerySnapshot homeSnapshot =
usersRef.doc(post.authorId).collection('users').get();
to this:
QuerySnapshot homeSnapshot =
await usersRef.doc(post.authorId).collection('users').get();

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/

Flutter : Facing an error like - The argument type 'Map<String, dynamic>?' can't be assigned to the parameter type 'Map<String, Object?>'

I am practicing with flutter SQFLite. That's why I create a model for user info. Here is my model code-
class Contact {
static const tblContact = "contacts";
static const colId = "id";
static const colName = "name";
static const colMobile = "mobile";
Contact({
this.id,
this.name = '',
this.mobile = '',
});
int? id;
String name;
String mobile;
Map<String, dynamic>? toMap() => {
"id": colId,
"name": colName.toString(),
"mobile": colMobile.toString(),
};
factory Contact.fromMap(Map<String, dynamic> json) =>
Contact(name: json[colName], mobile: json[colMobile]);
}
and then I create a database helper for insert and fetch data from database. But I faced a problem to insert value ( The argument type 'Map<dynamic, dynamic>?' can't be assigned to the parameter type 'Map<String, Object?>' ). Here is my database helper code -
import 'dart:io';
......
.......
class DatabaseHelper {
static const _databaseName = "ContactData.db";
static const _databaseVersion = 1;
//<====== Singleton Class
DatabaseHelper._();
static final DatabaseHelper instance = DatabaseHelper._();
Database? _database;
Future<Database?> get database async {
if (_database != null) {
return _database;
} else {
_database = await _initDatabase();
return _database;
}
}
//CREATE DATABASE
_initDatabase() async {
Directory dataDirectory = await getApplicationDocumentsDirectory();
String dbPath = join(dataDirectory.path, _databaseName);
print(dbPath);
return await openDatabase(dbPath,
version: _databaseVersion, onCreate: _onCreate);
}
//CREATE TABLE
_onCreate(Database db, int version) async {
db.execute('''
CREATE TABLE ${Contact.tblContact}(
${Contact.colId} INTEGER PRIMARY KEY AUTOINCREMENT,
${Contact.colName} STRING NOT NULL,
${Contact.colMobile} STRING NOT NULL
);
''');
print("Done on Create");
}
//<=================== ADD DATA
Future<int> insertContact(Contact contact) async {
Database? db = await database;
return await db!.insert(Contact.tblContact, contact.toMap());
}
//<==================== Read Data
Future<List<Contact>> fetchContacts() async {
Database? db = await database;
List<Map<String, dynamic>> contacts = await db!.query(Contact.tblContact);
print("Done Fetch");
return contacts.length == 0
? []
: contacts.map((x) => Contact.fromMap(x)).toList();
}
}
Error :
Where is my problem and what I missed ? Please someone help me to solve this.
Update:
I change argument type "Map<dynamic, dynamic>?" to "Map<String, dynamic>?" but now I found another error .
The argument type 'Map<String, dynamic>?' can't be assigned to the parameter type 'Map<String, Object?>'.
Recent Error:
You are getting this error because in insert function the Map type is <String, Object?> and you are passing a map that's type is <dynamic, dynamic>. try changing
Map<dynamic, dynamic>? toMap() => {
"id": colId,
"name": colName.toString(),
"mobile": colMobile.toString(),
};
factory Contact.fromMap(Map<dynamic, dynamic> json) =>
Contact(name: json[colName], mobile: json[colMobile]);
to
//You don't need to pass id because it's auto incremented
[ for null safety Use Map<String, Object?> not Map<String, Object>?]
Map<String, Object?> toMap() => {
"name": colName.toString(),
"mobile": colMobile.toString(),
};
factory Contact.fromMap(Map<String, Object?> json) =>
Contact(name: json[colName], mobile: json[colMobile]);
Your DB says that he wants a map like
Map<String, Object>
here the map's key must be a String
And you are passing a map with dynamic type of key
so change the key of your map from dynamic to String
Change this map type
Map<dynamic, dynamic>? toMap() => {
"id": colId,
"name": colName.toString(),
"mobile": colMobile.toString(),
};
to
Map<String, dynamic>? toMap() => {
"id": colId,
"name": colName.toString(),
"mobile": colMobile.toString(),
};
After that you will get another error like
The argument type 'Map<String, dynamic>?' can't be assigned to the parameter type 'Map<String, Object?>'.
Now at first we have to undertand what that Map<String, Object?> mean?
The type Object is your maps value must me a specific type of Data like int double String or any Custom Object because SQL Database store data in column and each column must mantain a specific data type so try like this
Map<String, Object>? toMap() => {
"id": colId,
"name": colName.toString(),
"mobile": colMobile.toString(),
};
Change
Map<dynamic, dynamic>? toMap() => {
"id": colId,
"name": colName.toString(),
"mobile": colMobile.toString(),
};
to
Map<String, dynamic>? toMap() => {
"id": colId,
"name": colName.toString(),
"mobile": colMobile.toString(),
};

can't receive the array to model

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;
}
}

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