jsonEncode generating error while converting object to jsonstring in flutter - flutter

For explaining what I am facing problem while creating a jsonstring from object list,I have created this basic demo,
actually I am trying to create a backup file for saving records but I am getting an error while jsonEncode.
getting following error
Converting object to an encodable object failed: Instance of 'TransactionModel'
class TransactionModel {
String id;
bool isexpense;
DateTime date;
double amount;
TransactionModel({
this.amount = 0.00,
required this.id,
this.isexpense = true,
required this.date,
});
Map<String, dynamic> toJson() {
return {
'id': id,
'isexpense': isexpense,
'date': date,
'amount': amount,
};
}
}
void main() {
List<TransactionModel> trans = [
TransactionModel(
date: DateTime.now(),
id: '1',),
];
String result = jsonEncode(trans);//error bcz of jsonEncode
print(result);
}

You can't encode an object with custom property like DateTime, you need first convert it to map, then encode it, try this:
void main() {
List<TransactionModel> trans = [
TransactionModel(
date: DateTime.now(),
id: '1',),
];
var listOfMap = trans.map((e) => e.toJson()).toList();
String result = jsonEncode(listOfMap);
print(result);
}

Related

getting an error Converting object to an encodable object failed: Instance of 'TransactionModel' while backup of box data in flutter

I am trying to do backup of hive box data to a json file, so that I can use it for restoring data if data is lost,
I am calling a function with on pressed of text button to do this task.
but I am getting an error regarding converting failure.
Converting object to an encodable object failed: Instance of 'TransactionModel'
here are models
#HiveType(typeId: 0)
class CategoryModel extends HiveObject
{
#HiveField(0)
String title;
#HiveField(1)
String iconurl;
CategoryModel({required this.title, required this.iconurl});
Map<String, dynamic> toJson() {
return {
'title': title,
'iconurl': iconurl,
};
}
factory CategoryModel.fromjson(Map<String, dynamic> map) {
return CategoryModel(
title: map['title'],
iconurl: map['iconurl']);
}
}
and
#HiveType(typeId: 1)
class TransactionModel extends HiveObject{
#HiveField(0)
String id;
#HiveField(1)
CategoryModel category;
#HiveField(2)
String paymentmode;
#HiveField(3)
bool isexpense;
#HiveField(4)
DateTime date;
#HiveField(5)
String note;
#HiveField(6)
double amount;
TransactionModel(
{
this.amount = 0.00,
required this.id,
required this.category,
required this.paymentmode,
this.isexpense = true,
required this.date,
this.note = 'No Note'});
Map<String, dynamic> toJson() {
return {
'id': id,
'category': category.toJson(),
'paymentmode': paymentmode,
'isexpense': isexpense,
'date': date,
'note':note,
'amount':amount,
};
}
factory TransactionModel.fromjson(Map<String, dynamic> map) {
return TransactionModel(
id: map['id'],
category: CategoryModel.fromjson(map['category']),
paymentmode: map['paymentmode'],
isexpense: map['isexpense'],
date: map['date'],
note: map['note'],
amount:map['amount'],
);
}
}
Here is the function for creating backup file of hive box data
Future<void> _createBackupFile() async {
File backupFile = File('${Directory.systemTemp.path}/logic.json');
try {
await backupFile.writeAsString(jsonEncode(Hive.box<TransactionModel>('ebook').values));
} catch (e) {
print('Error is :'+e.toString());
}
}
I found my mistake...
it can not encode directly to some custom datatype like DateTime, so need to convert into map before encode...
Map<String, dynamic> toJson() {
return {
'id': id,
'category': category.toJson(),
'paymentmode': paymentmode,
'isexpense': isexpense,
'date': date.toString(),//corrected from date to date.toString()
'note':note,
'amount':amount,
};
}

How to assign List<dynamic> to List<Khana>, where Khana is a model class in a parameter in Flutter-Firestore?

Actually, I am trying to get data from firebase and I am suffering from the Error:
Expected a value of type List < Khana >, but got one of type 'List< dynamic >'
I am getting data from the firebase, my fetchData function is:
Future<void> fetchAndSetOrder() async {
try {
await collectionRef.get().then((querySnapshot) {
for (var result in querySnapshot.docs) {
debugPrint("${result.runtimeType}=> ${result.data()}");
Orders newOrder = Orders.fromFirestore(result);
debugPrint("\n new order : $newOrder");
// _Order.add(newOrder);
debugPrint("new order added");
// _Order.add(Orders.fromMap(result as Map));
}
});
} catch (e) {
debugPrint("Error during Fetch:- $e");
}
}
and the Orders.fromFirestore constructor is:
factory Orders.fromFirestore(DocumentSnapshot<Object?> snapshot) {
final data = snapshot.data() as LinkedHashMap<String, dynamic>;
debugPrint("Inside From Firestore Function");
return Orders(
khana: data['khana'], // here is the error...
orderNumber: data['orderNumber'],
userId: data['userId'],
paymentCash: data['paymentCash'],
dateTime: data['dateTime'],
);
}
Orders class has:
class Orders{
List<Khana> khana; // this is another ModelClass
String userId;
int orderNumber;
DateTime dateTime;
bool paymentCash;
Orders({
required this.khana,
required this.userId,
required this.orderNumber,
required this.dateTime,
required this.paymentCash,
});
}
so, the issue is how can I read List from the firestore as a List ? Any other possible way to solve this issue.
My Khana Model is:
import 'dart:convert';
class Khana {
String mealName;
int id;
int price;
int quantity;
Khana({
required this.mealName,
required this.price,
required this.quantity,
required this.id,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'mealName': mealName});
result.addAll({'id': id});
result.addAll({'price': price});
result.addAll({'quantity': quantity});
return result;
}
factory Khana.fromMap(Map<String, dynamic> map) {
return Khana(
mealName: map['mealName'] ?? '',
id: map['id']?.toInt() ?? 0,
price: map['price']?.toInt() ?? 0,
quantity: map['quantity']?.toInt() ?? 0,
);
}
String toJson() => json.encode(toMap());
factory Khana.fromJson(String source) => Khana.fromMap(json.decode(source));
}
I am trying to read a List from the firestore snapshot.data(), it says it's return data type is List, and I want this list to be assigned to the List of my own ModelClass (i.e Khana), and I am not able to do that.
I even tried
factory Orders.fromFirestore(DocumentSnapshot<Object?> snapshot) {
final data = snapshot.data() as LinkedHashMap<String, dynamic>;
debugPrint("Inside From Firestore Function");
return Orders(
khana: data['khana'] as List<Khana>,
orderNumber: data['orderNumber'],
userId: data['userId'],
paymentCash: data['paymentCash'],
dateTime: data['dateTime'],
);
}
but got the same issue :(
Change your khana to this
khana: List<Khana>.from(data['khana'].map((x)=>Khana.fromJson(x)));

How to Save invoice in firestore flutter where invoice number is auto increment?

I am looking for this for a very long time but could not find a solution.
here is my code for uploading invoices into firestore database. I can save with a random invoice number what I dont want. I want to save the invoice number like below:
invoiceNumber: 20220312001, 20220312002, 202203003 ....
here 20220312 is current datetime in 'yyyyMMdd' formate.
Please help me if anybody knows. Or maybe any other logical invoice number with increment format that I can save is also okay for me.
Future<String> uploadInvoices({
required double amount,
// required List<CartItem> products,
required String branchName,
required String brachCompanyKey,
}) async {
String res = 'Some Error Occurred';
try {
DateTime currentDate = DateTime.now();
String formatedDate = DateFormat('yyyyMMdd').format(currentDate);
String invNum = formatedDate;
/* String invNum = formatedDate + andIncrementInt */
Invoice invoice = Invoice(
id: invNum,
amount: amount,
// products: products,
dateTime: DateTime.now(),
branchName: branchName,
companyKey: brachCompanyKey,
);
_firestore.collection('invoices').doc(invNum).set(invoice.toJson());
res = 'success';
} catch (e) {
res = e.toString();
}
return res;
}
// invoice model here...
class Invoice {
final String id;
final double amount;
// final List<CartItem> products;
final DateTime dateTime;
final String branchName;
final String companyKey;
Invoice({
required this.id,
required this.amount,
// required this.products,
required this.dateTime,
required this.branchName,
required this.companyKey,
});
Map<String, dynamic> toJson() => {
'id': id,
'amount': amount,
// 'products': products,
'dateTime': dateTime,
'branchName': branchName,
'companyKey': companyKey,
};
static Invoice fromSnap(DocumentSnapshot snap) {
var snapshot = snap.data() as Map<String, dynamic>;
return Invoice(
id: snapshot['id'],
amount: snapshot['amount'],
// products: snapshot['products'],
dateTime: snapshot['dateTime'],
branchName: snapshot['branchName'],
companyKey: snapshot['companyKey'],
);
}
}

How to fix Flutter Expected a value of type 'Map<String, dynamic>', but got one of type 'List<dynamic>'

I'm developing a web app using Flutter Web and RESTful API for backend.
So, I'm trying the fetch the data from the api, serialize it by using Flutter Models, then return the result.
The Problem is, I'm getting this result
Expected a value of type 'Map<String, dynamic>', but got one of type 'List<dynamic>'
How to fix this ?
Here's my flutter codes:
models
// To parse this JSON data, do
//
// final medicalRecordsModel = medicalRecordsModelFromJson(jsonString);
import 'dart:convert';
class MedicalRecordsModel {
MedicalRecordsModel({
this.id,
this.category,
this.fileName,
this.dateTimestamp,
this.description,
this.upload,
this.patientName,
this.age,
this.address,
this.userId,
this.patientId,
this.isActive,
});
final String id;
final String category;
final String fileName;
final String dateTimestamp;
final String description;
final String upload;
final String patientName;
final String age;
final String address;
final dynamic userId;
final int patientId;
final bool isActive;
factory MedicalRecordsModel.fromJson(Map<String, dynamic> json) {
return MedicalRecordsModel(
id: json["id"],
category: json["category"],
fileName: json["fileName"],
dateTimestamp: json["dateTimestamp"],
description: json["description"],
upload: json["upload"],
patientName: json["patientName"],
age: json["age"],
address: json["address"],
userId: json["userId"],
patientId: json["patientId"],
isActive: json["isActive"],
);
}
}
API Connection
import 'dart:convert';
import 'dart:developer';
import 'dart:async';
import 'package:app/src/constants/medical_records.dart';
import 'package:app/src/models/medical_records/medical_records.dart';
import 'package:app/src/pages/Medical-Records/medical_record.dart';
import 'package:http/http.dart' as http;
class MedicalRecordsManager {
var client = http.Client();
var url = ConstantMedicalRecords.medical_records_api;
Future<MedicalRecordsModel> getRecords() async {
var url = ConstantMedicalRecords.medical_records_api;
log('$url');
try {
final response = await client.get(url);
if (response.statusCode == 200) {
return MedicalRecordsModel.fromJson(jsonDecode(response.body));
// print(recordsModel);
}
} catch (Exception) {
print(Exception);
print("Error occured");
}
}
}
Here is the JSON data I want to get
{
"id": "103",
"category": "DOCUMENT",
"fileName": "Check Up",
"dateTimestamp": "2021-02-1012:59:46",
"description": "string",
"upload": "String",
"patientName": "1",
"age": "25",
"address": "Earth",
"userId": null,
"patientId": 12,
"isActive": true
}
Please help me with this one.
you can do it like that
MedicalRecordsModel.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
change the getRecord as follows
Future<MedicalRecordsModel> getRecords() async {
var url = ConstantMedicalRecords.medical_records_api;
log('$url');
try {
final response = await client.get(url);
if (response.statusCode == 200) {
return MedicalRecordsModel.fromJson(jsonDecode(response.body)[0]);
// print(recordsModel);
}
} catch (Exception) {
print(Exception);
print("Error occured");
}
}
I think jsonDecode gives list of Maps therefore your json map is the first element of that list.
This code wiil work as you expected:
import 'package:json_helpers/json_helpers.dart';
void main() {
// responseBody is the same response.body
// When response is a list of objects
final list = responseBody1.jsonList((e) => MedicalRecordsModel.fromJson(e));
var obj = list[0];
print(obj.category);
print(obj.fileName);
// When response is an object
obj = responseBody2.json((e) => MedicalRecordsModel.fromJson(e));
print(obj.category);
print(obj.fileName);
}
final responseBody1 = '''
[
{
"id":"103",
"category":"DOCUMENT",
"fileName":"Check Up",
"dateTimestamp":"2021-02-1012:59:46",
"description":"string",
"upload":"String",
"patientName":"1",
"age":"25",
"address":"Earth",
"userId":null,
"patientId":12,
"isActive":true
}
]''';
final responseBody2 = '''
{
"id":"103",
"category":"DOCUMENT",
"fileName":"Check Up",
"dateTimestamp":"2021-02-1012:59:46",
"description":"string",
"upload":"String",
"patientName":"1",
"age":"25",
"address":"Earth",
"userId":null,
"patientId":12,
"isActive":true
}''';
class MedicalRecordsModel {
final String id;
final String category;
final String fileName;
final String dateTimestamp;
final String description;
final String upload;
final String patientName;
final String age;
final String address;
final dynamic userId;
final int patientId;
final bool isActive;
MedicalRecordsModel({
this.id,
this.category,
this.fileName,
this.dateTimestamp,
this.description,
this.upload,
this.patientName,
this.age,
this.address,
this.userId,
this.patientId,
this.isActive,
});
factory MedicalRecordsModel.fromJson(Map<String, dynamic> json) {
return MedicalRecordsModel(
id: json['id'] as String,
category: json['category'] as String,
fileName: json['fileName'] as String,
dateTimestamp: json['dateTimestamp'] as String,
description: json['description'] as String,
upload: json['upload'] as String,
patientName: json['patientName'] as String,
age: json['age'] as String,
address: json['address'] as String,
userId: json['userId'] as String,
patientId: json['patientId'] as int,
isActive: json['isActive'] as bool,
);
}
}
Output:
DOCUMENT
Check Up
DOCUMENT
Check Up
That is, when response is a list of objects:
final list = response.body.jsonList((e) => MedicalRecordsModel.fromJson(e));
When response is an object:
final object = response.body.json((e) => MedicalRecordsModel.fromJson(e));
If you don't know what the result is, then you can try both methods.
response.body.json((e) => Model.fromJson(e));
response.body.jsonList((e) => Model.fromJson(e));
If you have already decoded a JSON string and want to convert the result (or part of it), you can use the following methods:
If the type of the decoded value is Map:
final object = value.json((e) => Model.fromJson(e));
If the type of the decoded value is List:
final objects = value.json((e) => Model.fromJson(e));
Every response is sended and received as text, which can be converted to the
Map Format with the dart inbuilt core library import 'dart:convert';.
So the response from the request can be treated like this.
final res = await http.post(Uri.parse(url), body: json.encode({
'userId': uid,
'email': email,
}),
head body: json.encode({
'userId': uid,
'email': email,
}),
headers: {'Content-Type': 'application/json', 'token64': token});
here json.encode() is used to convert to String from Map.
now res variable contain the response which is also a string which can be convert to the Map with json.decode() like this.
final data = json.decode(res);
when working with the data sometimes we occur errors like Map is not a type of Map<String, String> etc.
Which can be solved by type casting the res, like this.
Map<String, String> notification = Map<String, String>.from(data['notification']);
I see these type casting method used in the The boring Flutter Development show in Youtube.
I faced the same kind of problem after I built an API and tried consuming it in flutter. I first extracted the data and check if the extracted data is null. When the condition is false, I made a list loadStudents that will hold the data after the loop. This is what worked out for me after a ton of stress looking for solutions online.

How to save List<Object> to SharedPreferences in Flutter?

I have a list of favorite music, which I retrieve from music when the app is opened for the first time, the app gets a favorite music list from favorite. I want to save this list to shared
preferences.List<Music> favoriteMusic = new List<Music>();
where music class is:
class Music {
final int id;
final String name, size, rating, duration, img;
bool favorite;
Music({
this.id,
this.rating,
this.size,
this.duration,
this.name,
this.img,
this.favorite,
});
factory Music.fromJson(Map<String, dynamic> jsonData){
return Music(
id: jsonData['id'],
rating: jsonData['rating'],
size: jsonData['size'],
duration: jsonData['duration'],
name: jsonData['name'],
img: jsonData['img'],
favorite: false,
);
}
}
How can I save favorite music list?
You should do these steps
to save the object:
convert your object to map with toMap() method
encode your map to string with encode(...) method
save the string to shared preferences
for restoring your object:
decode shared preference string to a map with decode(...) method
use fromJson() method to get your object
UPDATE FULL SAMPLE
import 'dart:convert';
void main() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
// Encode and store data in SharedPreferences
final String encodedData = Music.encode([
Music(id: 1, ...),
Music(id: 2, ...),
Music(id: 3, ...),
]);
await prefs.setString('musics_key', encodedData);
// Fetch and decode data
final String musicsString = await prefs.getString('musics_key');
final List<Music> musics = Music.decode(musicsString);
}
class Music {
final int id;
final String name, size, rating, duration, img;
bool favorite;
Music({
this.id,
this.rating,
this.size,
this.duration,
this.name,
this.img,
this.favorite,
});
factory Music.fromJson(Map<String, dynamic> jsonData) {
return Music(
id: jsonData['id'],
rating: jsonData['rating'],
size: jsonData['size'],
duration: jsonData['duration'],
name: jsonData['name'],
img: jsonData['img'],
favorite: false,
);
}
static Map<String, dynamic> toMap(Music music) => {
'id': music.id,
'rating': music.rating,
'size': music.size,
'duration': music.duration,
'name': music.name,
'img': music.img,
'favorite': music.favorite,
};
static String encode(List<Music> musics) => json.encode(
musics
.map<Map<String, dynamic>>((music) => Music.toMap(music))
.toList(),
);
static List<Music> decode(String musics) =>
(json.decode(musics) as List<dynamic>)
.map<Music>((item) => Music.fromJson(item))
.toList();
}
Flutter's shared_preferences plugin has a method: setStringList(String key, List<String> value), so you can just write serializer for your objects.
Convert it to a string, you can store it
import 'dart:convert';
...
var s = json.encode(myList);
// or var s = jsonEncode(myList);
json.decode() //convert a string to List when you load it
For noob folks like me who want to understand a bit more about the magic our dear friend Hamed did in his answer, or want to adapt his solution to more complex classes with lists/other classes, check out these two links:
https://bezkoder.com/dart-flutter-parse-json-string-array-to-object-list/
https://bezkoder.com/dart-flutter-convert-object-to-json-string/
jsonEncode() and jsonDecode() are the same as json.encode() and json.decode()
simply use stringlist in shared preferences
basic syntax:
// read
final myStringList = prefs.getStringList('my_string_list_key') ?? [];
// write
prefs.setStringList('my_string_list_key', ['a', 'b', 'c']);
Firstly convert the object to a map. Then convert the map to a JSON string using jsonEncode and at the end save the JSON string to shared preferences
Sample example:
// import 'dart:convert';
Person person = Person('Mary', 30);
Map<String, dynamic> map = {
'name': person.name,
'age': person.age
};
String rawJson = jsonEncode(map);
prefs.setString('my_string_key', rawJson);
retrieve data
final rawJson = prefs.getString('my_string_key') ?? '';
Map<String, dynamic> map = jsonDecode(rawJson);
final person = Person(map['name'], map['age']);