Search code examples
jsonflutterdartsharedpreferences

How can I convert a list of custom objects within a parent object to (and from) JSON?


I have an app where I am trying to convert custom objects that the user inputs to and from JSON so I can store them in shared preferences.

Each object is a 'Resolution' and has multiple property types (Dates, Colors etc...) which I have no problem converting. So far so good...

My problem is that one of its properties is a List of type 'Commitment'. A 'Commitment' is ANOTHER custom object which also has properties of many different types (dates, doubles, strings etc..).

I've discovered I cannot simply convert the whole List property into a string and back, I need to run a specific conversion for all of the individual properties within each commitment within the list.

So I've basically got a nested conversion requirement...

The code for my 'RESOLUTION' is as follows

  class Resolution {
  final String id;
  String title;
  late DateTime? startDate;
  late DateTime? endDate;
  Color color;
  double progress;
  List<Commitment> commitments;
  bool isComplete;

  Resolution(
      {required this.id,
      required this.title,
      this.startDate,
      required this.endDate,
      this.color = Colors.orange,
      this.progress = 0,
      this.commitments = const [],
      this.isComplete = false});

  Map toMap() {
    return {
      'id': id,
      'title': title,
      'startDate': startDate!.toIso8601String(),
      'endDate': endDate!.toIso8601String(),
      'color': color.value.toString(),
      'progress': progress,
      'commitments': convertCommitmentsToJSON(commitments),
      'isComplete': isComplete,
    };
  }

  Resolution.fromMap(Map map)
      : id = map['id'],
        title = map['title'],
        startDate = DateTime.tryParse(map['startDate']),
        endDate = DateTime.tryParse(map['endDate']),
        color = Color(int.parse(map['color'])),
        progress = map['progress'],
        commitments = List<Commitment>.from(map['commitments']),
        isComplete = map['isComplete'];

  convertCommitmentsToJSON(commitments) {
    for (Commitment commitment in commitments) {
      commitment.toMap();
    }
  }

This works perfectly EXCEPT when it comes to that List Commitment property... As you can see I have written the following method

  convertCommitmentsToJSON(commitments) {
    for (Commitment commitment in commitments) {
      commitment.toMap();
    }
  }

Which I THINK is successfully converting the list to JSON by looping through the list contents and applying a conversion method I have created within the COMMITMENT class.

Assuming I have that half of the problem solved (which I may not so feel free to chip in), my issue is converting that JSON back into a list of Commitment objects...

I tried the following...

  convertCommitmentsFromJSON(List<Commitment> list) {
    for (Commitment commitment in list) {
      commitment.fromMap(jsonDecode(commitment));
    }
  }

...but I get the message 'The static method 'fromMap' can't be accessed through an instance'

The content of my (simplified) COMMITMENT class is as follows if it helps

class Commitment {
  String description;
  DateTime? endDate;

  Commitment({required this.description, this.endDate});

  Map<String, dynamic> toMap() => {
        'description': description,
        'endDate': endDate?.toIso8601String(),
      };

  static Commitment fromMap(Map<String, dynamic> json) => Commitment(
        description: json['description'],
        endDate: DateTime.tryParse(json['endDate']),
      );
}

Can anyone help? I'm relatively new to coding so perhaps i'm completely down the wrong path


REVISED CONVERSION CODE

Map toJson() {
    return {
      'id': id,
      'title': title,
      'startDate': startDate!.toIso8601String(),
      'endDate': endDate!.toIso8601String(),
      'color': color.value.toString(),
      'progress': progress,
      'commitments': convertCommitmentsToJSON(commitments),
      'isComplete': isComplete,
    };
  }

  Resolution.fromJson(Map map)
      : id = map['id'],
        title = map['title'],
        startDate = DateTime.tryParse(map['startDate']),
        endDate = DateTime.tryParse(map['endDate']),
        color = Color(int.parse(map['color'])),
        progress = map['progress'],
        commitments = convertCommitmentsFromJSON(List<Commitment>.from(map['commitments'])),
        isComplete = map['isComplete'];

  convertCommitmentsToJSON(commitments) {
    for (Commitment commitment in commitments) {
      commitment.toJson();
    }
  }

   
  convertCommitmentsFromJSON(List<Commitment> list) {
    for (Commitment commitment in list) {
      Commitment.fromJson;
    }
  }

Solution

  • Managed to resolve in the end with Kevin's help. syntax aside a key thing i was missing is that i wasn't actually returning a list in the original version of this function. I was simply looping through and doing nothing with the output.

    Kevin, thanks for the assist. Got there in the end! ;)

      static List<Commitment> convertCommitmentsFromJSON(List<dynamic> list) {
        List<Commitment> commitmentsList = [];
        if (list.isNotEmpty) {
          for (var item in list) {
            Commitment commitment = Commitment.fromJson(item);
            commitmentsList.add(commitment);
          }
        }
        return commitmentsList;
      }