1

I want to convert a list of 'Box' objects to a json file and also read it back in (json file to a list a 'Box' objects), but I'm a bit stuck on the implementation. I have written the below code, but I can only write a single 'Box' object to the json and convert a single 'Box' object back. When I try to do this with a list I hit errors like data that gets overwritten or just a single object that gets returned.

So in short, I want to write a List to json and convert json to List

I have the following data structure

Box model

class Box {
  final String nameBox;
  final List<Item> items;

  Box({@required this.nameBox, @required this.items});

  factory Box.fromJson(Map<String, dynamic> json) {
    var items = json['items'];
    List<Item> itemsList = items.cast<Item>();

    return new Box(
        nameBox: json["nameBox"],
        items: itemsList
    );
  }

  Map<String, dynamic> toJson() => {
        "nameBox": nameBox,
        "items": items,
      };
}

Box fromJson(String boxData) {
  return Box.fromJson(json.decode(boxData));
}

String toJson(Box box) {
  return json.encode(box.toJson());
}

Item model

class Item {
  final String itemName;
  final int quantity;

  Item({@required this.itemName, @required this.quantity});

  factory Item.fromJson(Map<String, dynamic> json) {
    return new Item(itemName: json["itemName"], quantity: json["quantity"]);
  }

  Map<String, dynamic> toJson() => {
        "itemName": itemName,
        "quantity": quantity,
      };
}

Item fromJson(String itemData) {
  return Item.fromJson(json.decode(itemData));
}

String toJson(Item item) {
  return json.encode(item.toJson());
}

writeToJson function

Future writeJson(Box box) async {
    final file = await _localFile;

    List<Box> tempRead = await returnBoxes();
    if (tempRead.isEmpty || tempRead == null) {
      return;
    }
    tempRead.add(box);
    file.writeAsString(json.encode(tempRead));
  }

readJson function

Future<List<Box>> returnBoxes() async {
    final file = await _localFile;

    List<Box> boxList = new List<Box>();

    Map<String, dynamic> content = await json.decode(file.readAsStringSync());

    boxList.add(Box.fromJson(content));

    return boxList;
  }

I also tried to cast the json content to a list, but then I hit some iterable errors. Any who can help me out?

1 Answer 1

1

JSON has this idiosyncrasy that everything is either an object or an array, and you don't know what you get until you decode it. Dart decodes the two json types into a Map<String, dynamic> and List<dynamic> respectively. (The reason that you get dynamic is because each of them could itself then be a value, a json array or a json object, recursively.)

Dart encodes a Dart object by calling toJson on it and a Dart list by emitting a [ then each member of the list then a ].

Knowing that, it's easy to encode and decode arrays/lists. (I removed all the unnecessary code.)

class Box {
  final String nameBox;
  final List<Item> items;

  Box({@required this.nameBox, @required this.items});

  factory Box.fromJson(Map<String, dynamic> json) => Box(
        nameBox: json['nameBox'],
        items: json['items'].map<Item>((e) => Item.fromJson(e)).toList(),
      );

  Map<String, dynamic> toJson() => {
        'nameBox': nameBox,
        'items': items,
      };
}

class Item {
  final String itemName;
  final int quantity;

  Item({@required this.itemName, @required this.quantity});

  factory Item.fromJson(Map<String, dynamic> json) => Item(
        itemName: json['itemName'],
        quantity: json['quantity'],
      );

  Map<String, dynamic> toJson() => {
        'itemName': itemName,
        'quantity': quantity,
      };
}

Future writeJson(Box box) async {
  final file = await _localFile;

  var boxes = await returnBoxes();
  /* I think you probably don't want this...
  if (boxes.isEmpty || boxes == null) {
    return;
  }*/
  // but rather, this
  if (boxes == null) boxes = [];
  boxes.add(box);
  await file.writeAsString(json.encode(boxes));
}

Future<List<Box>> returnBoxes() async {
  final file = await _localFile;

  // because the json is an array (i.e. enclosed in []) it will be decoded
  // as a Dart List<dynamic>
  List<dynamic> d = json.decode(await file.readAsString());
  // here we map the List<dynamic> to a series of Box elements
  // each dynamic is passed to the Box.fromJson constructor
  // and the series is formed into a List by toList
  return d.map<Box>((e) => Box.fromJson(e)).toList();
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.