How to save this nested class in Isar DB Flutter - flutter

I have the following 4 classes. In this, only the ProductGroup is saved, ProductVariant, ProductSize and ProductColor are not stored. Please help me with this.
product_group.dart
#Collection()
class ProductGroup {
late Id id;
#Index(caseSensitive: false)
late String productGroupName;
final productVariants = IsarLinks<ProductVariant>();
ProductGroup();
ProductGroup.fromJson(Map<String, dynamic> json) {
id = json['Id'];
productGroupName = json['PG'];
if (json['Ps'] != null) {
json['Ps'].forEach((variant) {
productVariants.add(ProductVariant.fromJson(variant));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['Id'] = id;
data['PG'] = productGroupName;
data['Ps'] = productVariants.map((variant) => variant.toJson()).toList();
return data;
}
}
product_variant.dart
#Collection()
class ProductVariant {
late Id id;
late String variantName;
final productSizes = IsarLinks<ProductSize>();
ProductVariant();
ProductVariant.fromJson(Map<String, dynamic> json) {
id = json['Id'];
variantName = json['St'];
if (json['Ss'] != null) {
json['Ss'].forEach((v) {
productSizes.add(ProductSize.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['Id'] = id;
data['St'] = variantName;
data['Ss'] = productSizes.map((v) => v.toJson()).toList();
return data;
}
}
product_size.dart
#Collection()
class ProductSize {
late Id id;
late String size;
final productColors = IsarLinks<ProductColor>();
ProductSize();
ProductSize.fromJson(Map<String, dynamic> json) {
id = json['Id'];
size = json['S'];
if (json['Cs'] != null) {
json['Cs'].forEach((v) {
productColors.add(ProductColor.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['Id'] = id;
data['S'] = size;
data['Cs'] = productColors.map((color) => color.toJson()).toList();
return data;
}
}
product_color.dart
#Collection()
class ProductColor {
late Id id;
late String colorName;
late String colorHexCode;
ProductColor();
ProductColor.fromJson(Map<String, dynamic> json) {
id = json['Id'];
colorName = json['C'];
colorHexCode = json['CC'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['Id'] = id;
data['C'] = colorName;
data['CC'] = colorHexCode;
return data;
}
}
I am parsing the json and saving it in Isar
convertJsonToIsar() async {
try {
// For testing purposes, loading Json from assets, in Prod, Json will be fetched from server
final String response = await rootBundle.loadString('assets/pr_dump.json');
final data = await json.decode(response);
List<ProductGroup> productGroupList = [];
data.forEach((item) {
productGroupList.add(ProductGroup.fromJson(item));
});
Isar _isar = getIsar();
_isar.writeTxnSync(() {
_isar.productGroups.putAllSync(productGroupList, saveLinks: true);
});
} catch (e) {
// Handle Error
print('Caught Error');
print(e.toString());
return 0;
}
}
Only the ProductGroup is stored, ProductVariant, ProductSize and ProductColor are not stored. Please help me with this.

Related

How to access JSON via field?

I have a JSON
jsonData
{
"data": {
"splashPage": {
"title": "Splash"
},
"homePage": {
"title": "Home"
}
}
}
List<String> accessField = ['data','splashPage'];
final out = accessField.map((e) => "['$e']").join();
Map jsonMapData = jsonDecode(jsonData);
Map<String, dynamic> splashPageJson = '${jsonMapData}$out' as Map<String, dynamic>;
print(splashPageJson);
I got an error can't access to splashPage.
_CastError (type 'String' is not a subtype of type 'Map<String, dynamic>' in type cast)
How can I access to splashPage from JSON?
Note: accessField is dynamic value
If I want to access splashPage, declaration
accessField = ['data','splashPage'];
If I want to access homePage, declaration
accessField = ['data','homePage'];
Is this what you want?
var jsonData = {
"data": {
"splashPage": {
"title": "Splash"
},
"homePage": {
"title": "Home"
}
}
}
Map jsonMapData = jsonDecode(jsonData);
List<String> accessField = ['data','splashPage'];
Map<String, dynamic> requiredResult = jsonMapData[accessField[0]][accessField[1]];
Here's the solution:
First import:
import 'dart:convert';
To store JSON into the map:
final Map<String, dynamic> map = json.decode('{"data":{"splashPage":{"title":"Splash"},"homePage":{"title":"Home"}}}');
To print your requirement:
print(map["data"]["splashPage"]["title"]);
Code for your Model:
class Model {
Model({
this.data,
});
Model.fromJson(Map<String, dynamic> json) {
data = json["data"] != null ? Data.fromJson(json["data"]) : null;
}
Data? data;
Map<String, dynamic> toJson() {
final Map<String, dynamic> map = <String, dynamic>{};
if (data != null) {
map["data"] = data?.toJson();
}
return map;
}
}
class Data {
Data({
this.splashPage,
this.homePage,
});
Data.fromJson(Map<String, dynamic> json) {
splashPage = json["splashPage"] != null
? SplashPage.fromJson(json["splashPage"])
: null;
homePage =
json["homePage"] != null ? HomePage.fromJson(json["homePage"]) : null;
}
SplashPage? splashPage;
HomePage? homePage;
Map<String, dynamic> toJson() {
final Map<String, dynamic> map = <String, dynamic>{};
if (splashPage != null) {
map["splashPage"] = splashPage?.toJson();
}
if (homePage != null) {
map["homePage"] = homePage?.toJson();
}
return map;
}
}
class HomePage {
HomePage({
this.title,
});
HomePage.fromJson(Map<String, dynamic> json) {
title = json["title"];
}
String? title;
Map<String, dynamic> toJson() {
final Map<String, dynamic> map = <String, dynamic>{};
map["title"] = title;
return map;
}
}
class SplashPage {
SplashPage({
this.title,
});
SplashPage.fromJson(Map<String, dynamic> json) {
title = json["title"];
}
String? title;
Map<String, dynamic> toJson() {
final Map<String, dynamic> map = <String, dynamic>{};
map["title"] = title;
return map;
}
}
Code for your usage:
final Model model = Model.fromJson(
json.decode(
'{"data":{"splashPage":{"title":"Splash"},"homePage":{"title":"Home"}}}',
),
);
print(model.data?.splashPage?.title ?? "");
print(model.data?.homePage?.title ?? "");
Don't forgot to import:
import 'dart:convert';
This is a question about conversion of Json data format to native data model. If you publish the Json data earlier, the problem may not be so complicated
try this.
void test() {
var json =
'{"data":{"splashPage":{"title":"Splash"},"homePage":{"title":"Home"}}}';
var map = jsonDecode(json) as Map<String, dynamic>;
var model = DataResponseModel.fromJson(map);
pr(model.data?.homePage?.title); // Home
pr(model.data?.splashPage?.title); // Splash
}
class TitleModel {
String? title;
TitleModel({required this.title});
factory TitleModel.fromJson(Map<String, dynamic> map) =>
TitleModel(title: map['title']);
}
class DataModel {
TitleModel? splashPage;
TitleModel? homePage;
DataModel({required this.splashPage, this.homePage});
factory DataModel.fromJson(Map<String, dynamic> map) => DataModel(
splashPage: TitleModel.fromJson(map['splashPage']),
homePage: TitleModel.fromJson(map['homePage']),
);
}
class DataResponseModel {
DataModel? data;
DataResponseModel({required this.data});
factory DataResponseModel.fromJson(Map<String, dynamic> map) =>
DataResponseModel(
data: DataModel.fromJson(map['data']),
);
}

HTTP GET request result into array

so i have this http req payload, and i want to push it into an array, can someone help me?
The payload
{
"status":200,
"length":3,
"results":[
{
"_id":"60cd70b3fb9fe400117e8c6b",
"title":"Welcome to xxx",
"body":"Welcome to xx! We’re excited that everyone’s here and hope your ready for an epic weekend."
},
{
"_id":"60cd70b3fb9fe400117e8c6c",
"title":"Lunch Info",
"body":"Lunch is from our generous sponsors Lorem Ipsum! It will be served in the left atrium under the palm trees."
},
{
"_id":"60cd70b3fb9fe400117e8c6d",
"title":"Leash Dogs",
"body":"A friendly reminder that dogs must be leashed at all times, no matter how cute <3"
}
]
}
My Provider Code [UPDATED]
//So I've tried to debug on my own, and number 1 and number 2 is printed, while number 3 is not. I suspect its because of the way I handle extractedData.
class Announcements {
int? status;
int? length;
List<Results>? results;
Announcements(
{required this.status, required this.length, required this.results});
Announcements.fromJson(Map<String, dynamic> json) {
status = json['status'];
length = json['length'];
if (json['results'] != null) {
results = [];
json['results'].forEach((v) {
results!.add(new Results.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['length'] = this.length;
if (this.results != null) {
data['results'] = this.results!.map((v) => v.toJson()).toList();
}
return data;
}
}
// so i've used your online converter json
class Results {
String? sId;
String? title;
String? body;
Results({required this.sId, required this.title, required this.body});
Results.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
title = json['title'];
body = json['body'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['_id'] = this.sId;
data['title'] = this.title;
data['body'] = this.body;
return data;
}
}
class AnnouncementProvider with ChangeNotifier {
AnnouncementProvider(String? token, items);
List _items = [];
List get items {
return [..._items];
}
// List<Announcements> parseAnnouncement(String responseBody) {
// }
Future<List<Announcements>> fetchAnnouncements(String authToken) async {
//var url = Uri.https('api-staging.xxx.us.org', '/1.0/announcements');
final response = await http.get(
Uri.parse('https://api-staging.xxx.us.org/1.0/announcements'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $authToken',
},
);
print(response.body);
final t = Announcements.fromJson(response.body as Map<String, dynamic>);
print(t.results);
return t.results;
}
}
What I need to know is, how do I return the list correctly, since the print(t.results) is actually not printed for some reason, so now it only shows "An error has occured" in my interface.
Thanks for helping!
Consider making a Dart Model object for the same, I would highly recommend you to do so because this is guaranteed serialization and type safe
For your case I used an imaginary name FoodItems for the type of data you received from your api endpoint
class FoodItems {
int status;
int length;
List<Results> results;
FoodItems({this.status, this.length, this.results});
FoodItems.fromJson(Map<String, dynamic> json) {
status = json['status'];
length = json['length'];
if (json['results'] != null) {
results = new List<Results>();
json['results'].forEach((v) {
results.add(new Results.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['length'] = this.length;
if (this.results != null) {
data['results'] = this.results.map((v) => v.toJson()).toList();
}
return data;
}
}
class Results {
String sId;
String title;
String body;
Results({this.sId, this.title, this.body});
Results.fromJson(Map<String, dynamic> json) {
sId = json['_id'];
title = json['title'];
body = json['body'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['_id'] = this.sId;
data['title'] = this.title;
data['body'] = this.body;
return data;
}
}
Now you can easily cast your response.body to the FoodItems class using fromJson method and then get the desired list of Results and then iterate over it
In my honest opinion, it makes it much simpler this way
Note: I would highly recommend reading the following
This is a nice article from the Flutter Developers themselves
Android Studio Plugin to do the serialization for you
Online converter

How return a Future<List<PokemonModel>> to use data in widgets?

My PokemonModel and Results class, i wan't return a List
class PokemonModel {
int count;
String next;
String previous;
List<Results> results;
PokemonModel({this.count, this.next, this.previous, this.results});
PokemonModel.fromJson(Map<String, dynamic> json) {
count = json['count'];
next = json['next'];
previous = json['previous'];
if (json['results'] != null) {
results = [];
json['results'].forEach((v) {
results.add(new Results.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['count'] = this.count;
data['next'] = this.next;
data['previous'] = this.previous;
if (this.results != null) {
data['results'] = this.results.map((v) => v.toJson()).toList();
}
return data;
}
}
class Results {
String name;
String url;
Results({this.name, this.url});
Results.fromJson(Map<String, dynamic> json) {
name = json['name'];
url = json['url'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['url'] = this.url;
return data;
}
}
I try use this on repository, i'll need ['next'], ['previous'] and results data to use in widgets but i cannot convert the data to a list of PokemonModel.
That's my current repository where i try get data.
class PokemonRepository implements IPokemonRepository {
Dio _dio;
final String url = 'https://pokeapi.co/api/v2/pokemon/';
PokemonRepository([Dio dio]) : _dio = dio ?? Dio();
#override
Future<List<PokemonModel>> getPokemons() async {
final response = await _dio.get(url);
final poke = PokemonModel.fromJson(response.data);
//how parse and return a list of pokemonmodel?
}
}
There are a couple of ways you can do it.
// method 1 (declarative/functional programming)
final List<PokemonModel> myList = response
.map<PokemonModel>((item) => PokemonModel.fromJson(item))
.toList();
return myList;
or
// method 2 (imperative)
final myList2 = <PokemonModel>[];
for (final Map<String, dynamic> item in response) {
myList2.add(PokemonModel.fromJson(item));
}
return myList2;
I've seen it done both ways. Both return the same result.

How to register multiple adapters with hive for single modal class

I am kind of new to flutter and working on the application where I need to save data locally to use it later when user will be offline.
I have a modal class with multiple inner classes:
Modal Class:
import 'package:hive/hive.dart';
part 'DownloadResponse.g.dart';
#HiveType(typeId: 1)
class DownloadResponse extends HiveObject {
#HiveField(0)
UserInfo userInfo;
#HiveField(1)
AppSetting appSetting;
#HiveField(2)
List<Seals> seals;
#HiveField(3)
String success;
#HiveField(4)
String message;
DownloadResponse(
{this.userInfo, this.appSetting, this.seals, this.success, this.message});
DownloadResponse.fromJson(Map<String, dynamic> json) {
userInfo = json['userInfo'] != null
? new UserInfo.fromJson(json['userInfo'])
: null;
appSetting = json['appSetting'] != null
? new AppSetting.fromJson(json['appSetting'])
: null;
if (json['seals'] != null) {
seals = new List<Seals>();
json['seals'].forEach((v) {
seals.add(new Seals.fromJson(v));
});
}
success = json['success'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.userInfo != null) {
data['userInfo'] = this.userInfo.toJson();
}
if (this.appSetting != null) {
data['appSetting'] = this.appSetting.toJson();
}
if (this.seals != null) {
data['seals'] = this.seals.map((v) => v.toJson()).toList();
}
data['success'] = this.success;
data['message'] = this.message;
return data;
}
}
#HiveType(typeId: 2)
class UserInfo extends HiveObject {
String fullName;
String mobileLastSyncDate;
UserInfo({this.fullName, this.mobileLastSyncDate});
UserInfo.fromJson(Map<String, dynamic> json) {
fullName = json['full_name'];
mobileLastSyncDate = json['mobile_last_sync_date'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['full_name'] = this.fullName;
data['mobile_last_sync_date'] = this.mobileLastSyncDate;
return data;
}
}
#HiveType(typeId: 3)
class AppSetting extends HiveObject {
String appWebviewHeight;
String appScreenHeaderSealScan;
String appScreenHeaderSealInfo;
String appScreenHeaderPicture1;
String appScreenHeaderPicture2;
AppSetting(
{this.appWebviewHeight,
this.appScreenHeaderSealScan,
this.appScreenHeaderSealInfo,
this.appScreenHeaderPicture1,
this.appScreenHeaderPicture2});
AppSetting.fromJson(Map<String, dynamic> json) {
appWebviewHeight = json['app_webview_height'];
appScreenHeaderSealScan = json['app_screen_header_seal_scan'];
appScreenHeaderSealInfo = json['app_screen_header_seal_info'];
appScreenHeaderPicture1 = json['app_screen_header_picture_1'];
appScreenHeaderPicture2 = json['app_screen_header_picture_2'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['app_webview_height'] = this.appWebviewHeight;
data['app_screen_header_seal_scan'] = this.appScreenHeaderSealScan;
data['app_screen_header_seal_info'] = this.appScreenHeaderSealInfo;
data['app_screen_header_picture_1'] = this.appScreenHeaderPicture1;
data['app_screen_header_picture_2'] = this.appScreenHeaderPicture2;
return data;
}
}
#HiveType(typeId: 4)
class Seals extends HiveObject {
String sealId;
String sealHtml;
List<Documents> documents;
Seals({this.sealId, this.sealHtml, this.documents});
Seals.fromJson(Map<String, dynamic> json) {
sealId = json['seal_id'];
sealHtml = json['seal_html'];
if (json['documents'] != null) {
documents = new List<Documents>();
json['documents'].forEach((v) {
documents.add(new Documents.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['seal_id'] = this.sealId;
data['seal_html'] = this.sealHtml;
if (this.documents != null) {
data['documents'] = this.documents.map((v) => v.toJson()).toList();
}
return data;
}
}
#HiveType(typeId: 5)
class Documents extends HiveObject {
String documentId;
String documentName;
String documentLink;
Documents({this.documentId, this.documentName, this.documentLink});
Documents.fromJson(Map<String, dynamic> json) {
documentId = json['document_id'];
documentName = json['document_name'];
documentLink = json['document_link'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['document_id'] = this.documentId;
data['document_name'] = this.documentName;
data['document_link'] = this.documentLink;
return data;
}
}
And this is my logic where I am trying to save data in the hive:
// We get the current app directory
WidgetsFlutterBinding.ensureInitialized();
final appDocDir = await getApplicationDocumentsDirectory();
// We initialize Hive and we give him the current path
Hive
..init(appDocDir.path)
..registerAdapter(DownloadResponseAdapter());
var box = await Hive.openBox('driverData');
//box.put('ew32', DownloadResponse('BMW','test', 2002));
UserInfo userInfo = downloadResponse.userInfo;
AppSetting appSetting = downloadResponse.appSetting;
List<Seals> sealList = downloadResponse.seals;
String success = downloadResponse.success;
String message = downloadResponse.message;
await box.put('driverData', DownloadResponse()
..userInfo = userInfo
..appSetting = appSetting
..seals = sealList
..success = success
..message = message);
print(box.get('driverData'));
I get this exception when box.put() runs:
Unhandled Exception: HiveError: Cannot write, unknown type: UserInfo. Did you forget to register an adapter
My question is how do I create and add multiple adapters with hive as my modal class has multiple classes?
I got the answer of the same. You will have all the adapters available in the automated generated file.
You just need to add them before saving data like this:
Hive
..init(appDocDir.path)
..registerAdapter(DownloadResponseAdapter())
..registerAdapter(UserInfoAdapter())
..registerAdapter(AppSettingAdapter())
..registerAdapter(SealsAdapter())
..registerAdapter(DocumentsAdapter()
);

Decode json flutter

I have this data format
message": [
{
"id": 15989,
"title": "xxx",
"body": "xxx",
"type": "abc",
"data_hash": "{\"id\":\"3098\",\"number\":1}",
}, .....]
If I write like this
print(message['data']['type']);
I can get abc, but if I write print(message['data']['data_hash']);, I get invalid arguments error. Why?
I want to get the number in data_hash.
This is the full code
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print("===== onMessage ====");
try {
print(message['data']['data_hash']);
} catch (e) {
print(e.toString());
}
});
data_hash row is a json. So you need to decode that row for use.
final data_hash_map = jsonDecode(message['data']['data_hash']);
print(data_hash_map); // { "id": 3098, "number": 1 }
print(data_hash_map["number"]); // for number
Decode your json as below
Map<String, dynamic> jsonData = jsonDecode(message)
I recommend to create a class to predefine the object as followed:
class Message {
int id;
String title;
String body;
String type;
DataHash dataHash;
message({this.id, this.title, this.body, this.type, this.dataHash});
Message.fromJson(Map<String, dynamic> json) {
id = json['id'];
title = json['title'];
body = json['body'];
type = json['type'];
dataHash = json['data_hash'] != null
? new DataHash.fromJson(json['data_hash'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['title'] = this.title;
data['body'] = this.body;
data['type'] = this.type;
if (this.dataHash != null) {
data['data_hash'] = this.dataHash.toJson();
}
return data;
}
}
class DataHash {
String id;
String number;
DataHash({this.id, this.number});
DataHash.fromJson(Map<String, dynamic> json) {
id = json['id'];
number = json['number'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['number'] = this.number;
return data;
}
}
You can call Message.fromJson(data) to decode.
Messsage message = Message.fromJson(data);
print(message.dataHash.number);
I hope this will work correctly
class _HomeState extends State<Mytimeoff> {
List<Map> list = [];
Map leaveRoot ={};
void getList() async {
var data = await http
.get('https:your api link');
leaveRoot = Map.from(json.decode(data.body));
setState(() {
for (Map js in leaveRoot['leavetype']) {
list.add(js);
}
});
print(jsonData);
}
#override
void initState() {
super.initState();
getList();
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}