Reputation: 3539
I've been trying to return a Map by calling the toJson functions of my classes, but I get NoSuchMethodError: Class '_InternalLinkedHashMap' has no instance method 'toJson'. So I'm assuming that this is not correct. The examples only contain single values that can convert to single values, but no handling of lists or Maps. So what's the proper way to handle serializing maps to JSON using json_serializer in Dart?
The class I'm trying to serialize:
class StudentDailyReport {
final DocumentReference documentReference;
Student student;
// CheckIn
String attendanceStatus;
bool checkInChanged;
DateTime checkedInTime;
DateTime date;
// CheckOut
bool get checkedOut => this.attendanceStatus == AttendanceStatus.checkedOut;
bool checkOutChanged;
DateTime checkedOutTime;
// Mood
Mood mood;
bool moodHasChanged;
TextEditingController moodController;
// Supplies
Supplies supplies;
// Notes
Note note;
TextEditingController noteController;
bool noteChanged;
// Meals
Map<Meal, MealRecord> mealRecords;
bool mealsChanged;
// Health
Map<int, HealthEntry> healthEntries;
bool healthChanged;
//PottyLog
PottyLog pottyLog;
bool get pottyLogChanged => pottyLog.hasChanged;
ActivityLog activityLog;
bool get activityLogChanged => activityLog.hasChanged;
set activityLogChanged(bool value) =>
activityLog = activityLog.copyWith(hasChanged: value);
List<CaptionedPhoto> photos;
factory StudentDailyReport.initialFromStudent(Student student) {
return StudentDailyReport(
student: student,
moodController: TextEditingController(),
healthEntries: {0: HealthEntry.empty()},
supplies: Supplies(),
pottyLog: PottyLog.empty(),
activityLog: ActivityLog());
}
StudentDailyReport.fromDocument(DocumentSnapshot document)
: documentReference = document.reference {
Map json = document.data;
// Ensure that the student has been converted and inserted as a student object
// into the json before calling.
this.student = json['student'];
this.mood = json['mood'] != null ? Mood.fromJson(json['mood']) : Mood();
this.attendanceStatus = json['attendanceStatus'] ?? AttendanceStatus.none;
this.checkedInTime = json['checkedInTime'] != null
? (json['checkedInTime'] as Timestamp).toDate()
: null;
this.checkedOutTime = json['checkedOutTime'] != null
? (json['checkedOutTime'] as Timestamp).toDate()
: null;
this.supplies = json['supplies'] != null
? Supplies.fromJson(json['supplies'])
: Supplies();
this.note = json['note'] != null ? Note.fromJson(json['note']) : Note();
noteController = TextEditingController(text: note.comment);
this.mealRecords = MealRecord.mapFromJsonList(json['mealRecords']);
this.healthEntries = json['healthEntries'] != null
? (json['healthEntries'] as List)
.map((json) => HealthEntry.fromJson(json))
.toList()
.asMap()
: {0: HealthEntry.empty()};
this.pottyLog = json["pottyLog"] != null
? PottyLog.fromJson(json["pottyLog"])
: PottyLog();
this.activityLog = json["activityLog"] != null
? ActivityLog.fromJson(json["activityLog"])
: ActivityLog();
this.photos = json['photos'] != null
? (json['photos'] as List)
.map((photoJson) => CaptionedPhoto.fromJson(photoJson))
.toList()
: List<CaptionedPhoto>();
this.checkInChanged = false;
this.checkOutChanged = false;
this.healthChanged = false;
this.mealsChanged = false;
this.noteChanged = false;
this.moodHasChanged = false;
this.moodController = TextEditingController();
}
bool validateMeals() {
return mealRecords.values.any((mealRecord) => !mealRecord.isValid);
}
/// Used to indicate when changes need to be saved.
bool get hasUnsavedChanges {
bool result;
if (moodHasChanged == null ||
checkInChanged == null ||
supplies.suppliesHasChanged == null ||
checkOutChanged == null ||
noteChanged == null ||
checkOutChanged == null ||
mealsChanged == null ||
healthChanged == null ||
pottyLogChanged == null ||
activityLogChanged == null) {
debugPrint("One of these is null!");
}
try {
result = moodHasChanged ||
checkInChanged ||
supplies.suppliesHasChanged ||
checkOutChanged ||
noteChanged ||
checkOutChanged ||
mealsChanged ||
healthChanged ||
pottyLogChanged ||
activityLogChanged;
} on Exception {
return false;
}
return result;
}
StudentDailyReport({
this.documentReference,
this.student,
this.date,
// Mood
this.mood = const Mood(),
this.moodHasChanged = false,
this.moodController,
// Check In
this.attendanceStatus = AttendanceStatus.none,
this.checkInChanged = false,
this.checkedInTime,
//Check Out
this.checkOutChanged = false,
this.checkedOutTime,
// Supplies
this.supplies,
this.mealRecords = const {},
this.mealsChanged = false,
// Notes
this.noteController,
this.note = const Note.empty(),
this.noteChanged = false,
// Health
this.healthEntries,
this.healthChanged = false,
//PottyLog
this.pottyLog,
//ActivityLog
this.activityLog,
this.photos,
}) {
// assertions
if (attendanceStatus == AttendanceStatus.present) {
assert(checkedInTime != null);
}
if (attendanceStatus == AttendanceStatus.checkedOut) {
assert(checkedOutTime != null);
}
this.date ??= DateTime.now();
this.noteController = TextEditingController();
this.moodController = TextEditingController();
}
StudentDailyReport copyWith({
DocumentReference documentReference,
Mood mood,
bool moodChanged,
bool checkInChanged,
DateTime checkedInTime,
bool checkedOut,
DateTime checkedOutTime,
bool checkOutChanged,
TextEditingController moodController,
String attendanceStatus,
Note note,
Supplies supplies,
TextEditingController notesController,
bool notesChanged,
TextEditingController suppliesController,
bool suppliesChanged,
bool hasUnsavedChanges,
Map<Meal, MealRecord> mealRecords,
bool mealsChanged,
Map<int, HealthEntry> todaysHealthEntries,
bool healthChanged,
PottyLog pottyLog,
bool pottyLogChanged,
ActivityLog activityLog,
bool activityLogChanged,
List<CaptionedPhoto> photos,
DateTime date,
}) {
return StudentDailyReport(
documentReference: documentReference ?? this.documentReference,
student: this.student,
mood: mood ?? this.mood,
moodHasChanged: moodChanged ?? this.moodHasChanged,
checkInChanged: checkInChanged ?? this.checkInChanged,
attendanceStatus: attendanceStatus ?? this.attendanceStatus,
checkedInTime: (attendanceStatus == AttendanceStatus.present &&
checkedInTime == null)
? DateTime.now()
: checkedInTime ?? this.checkedInTime,
moodController: this.moodController,
note: note ?? this.note,
noteController: this.noteController,
noteChanged: noteChanged ?? this.noteChanged,
supplies: supplies ?? this.supplies,
checkOutChanged: checkOutChanged ?? this.checkOutChanged,
checkedOutTime: attendanceStatus == AttendanceStatus.present &&
checkedOutTime == null
? DateTime.now()
: this.checkedOutTime,
mealRecords: mealRecords ?? this.mealRecords,
mealsChanged: mealsChanged ?? this.mealsChanged,
healthEntries: todaysHealthEntries ?? this.healthEntries,
healthChanged: healthChanged ?? this.healthChanged,
pottyLog: () {
PottyLog newPottyLog = pottyLog ??= this.pottyLog;
if (pottyLogChanged == false) {
return newPottyLog.copyWith(hasChanged: false);
}
return newPottyLog;
}(),
activityLog: activityLog ?? this.activityLog,
photos: photos ?? this.photos,
date: date ?? this.date);
}
String get fullName => student.fullName;
Map<String, dynamic> toJson() {
Map<String, dynamic> data = {};
if (this.mood != null && this.mood.mood != "" && this.moodHasChanged) {
data["mood"] = this.mood.toJson();
}
// attendance
if (this.checkInChanged || this.checkOutChanged) {
data["attendanceStatus"] = this.attendanceStatus;
}
if (this.checkInChanged) {
assert(checkedInTime != null);
data['checkedInTime'] = Timestamp.fromDate(this.checkedInTime);
}
if (this.checkOutChanged) {
assert(checkedOutTime != null);
data['checkedOutTime'] = Timestamp.fromDate(this.checkedOutTime);
}
if (this.supplies.suppliesHasChanged) {
data["supplies"] = this.supplies.toJson();
}
if (this.mealsChanged) {
data['mealRecords'] = this
.mealRecords
.values
.map((mealRecord) => mealRecord.toJson())
.toList();
}
if (this.noteChanged) {
data['note'] = this.note.toJson();
}
data['student'] = this.student.documentReference;
if (healthChanged) {
data['healthEntries'] = healthEntries.values
.map((healthEntry) => healthEntry.toJson())
.toList();
}
if (this.pottyLogChanged) {
data['pottyLog'] = this.pottyLog.toJson();
}
if (this.activityLogChanged) {
data['activityLog'] = this.activityLog.toJson();
}
return data;
}
StudentDailyReport updateWith(DocumentSnapshot documentChange) {
Map json = documentChange.data;
return StudentDailyReport(
documentReference: documentChange.reference,
student: student,
mood: json['mood'] != null ? Mood.fromJson(json['mood']) : mood,
attendanceStatus: json['attendanceStatus'] ?? attendanceStatus,
checkedInTime:
(json['checkedInTime'] as Timestamp)?.toDate() ?? checkedInTime,
checkedOutTime:
(json['checkedOutTime'] as Timestamp)?.toDate() ?? checkedOutTime,
supplies: json['supplies'] != null
? Supplies.fromJson(json['supplies'])
: supplies,
note: json['note'] != null ? Note.fromJson(json['note']) : note,
mealRecords: MealRecord.mapFromJsonList(json['mealRecords']),
healthEntries: json['healthEntries'] != null
? (json['healthEntries'] as List)
.map((json) => HealthEntry.fromJson(json))
.toList()
.asMap()
: healthEntries,
pottyLog: json["pottyLog"] != null
? PottyLog.fromJson(json["pottyLog"])
: pottyLog,
activityLog: json["activityLog"] != null
? ActivityLog.fromJson(json["activityLog"])
: activityLog,
photos: json['photos'] != null
? (json['photos'] as List)
.map((json) => CaptionedPhoto.fromJson(json))
.toList()
: []);
}
@override
String toString() {
return "Report for $fullName";
}
}
Upvotes: 0
Views: 169
Reputation: 6171
At the moment we do not support "complex" keys in Maps – Like Meal
.
Star this issue - https://github.com/dart-lang/json_serializable/issues/396
Upvotes: 1