Flutter converting Nested Object from Json returns null

1,812

Solution 1

I found it out :)

I have restructured my fromJson to this, especially the jsonDecode was important, because json["exercise "] was only a String.

PlanModel.fromJson(dynamic json) {
    name = json["name"];
    if (json["exercise"] != null) {
      exercise = [];
      jsonDecode(json["exercise"]).forEach((v) {
        exercise.add(Exercise.fromJson(v));
      });
    }}

now I can access it with

PlanModel item = snapshot.data[index];

item.exercise[0].timeGoal.toString()
    

Solution 2

Read this first.

You need to tweek this code a little to work for you but the idea is that; also read comment in the code.

if json string comes with [] those around, json.decode will decode it as List<Map>.

if it comes with {} this json.decode will decode it as Map.

note: be careful while using generics on json.decode I reccommend not to.

data inside the jsonString does not really corresponds with the values inside the fromJson function. json string which you have provided was not really good. so I think you will understand how to manipulate it for your needs.

also main constructor Exercise you can use for initial data.

import 'dart:convert';
class Exercise{
  Exercise({this.index, 
            this.name, 
            this.repGoal, 
            this.weightGoal, 
            this.setGoal});
  
  String index;
  String name;
  String repGoal;
  String weightGoal;
  String setGoal;


Exercise.fromJson(dynamic json) : 
    // anything that is wrapped around with this [] in json is converted as list
    // anything that is wrapped around with this {} is map
    index = json["exercise"][0]["index"].toString(),
    name = json["name"].toString(),
    repGoal = json["repGoal"].toString(),
    weightGoal = json["weightGoal"].toString(),
    setGoal = json["setGoal"].toString();
  
  
}

void main(){
  String jsonString = '{name: number 1, id: 56, exercise: [{"index":1,"weightGoal":[15,16,17], pause: [{"index":2}]}';
  Map json = json.decode(jsonString);
  Exercise.fromJson(json);
  
}
Share:
1,812
m123
Author by

m123

Updated on December 07, 2022

Comments

  • m123
    m123 over 1 year

    I have a Nested Object like this just a bit bigger:

    "name": "String",       
        "exercise": [               
                       {                
                       "index": 1,                                  
                       }            
                ],              
        "pause": [              
            {"index":2},                        
        ]           
    

    I convert the exercise and pause to a Json String and save them in a column in SQFLite.

    The problem

    When I read the Data everything works fine including the List (not nested) but both list's of nested Object are empty when I read a value of the nested object it gives an error.

    item.exercise[0].index.toString()
    
    Valid Value range is empty: 0
    

    When I read only item.exercise.toString() it returns []. Without != null ? [...] : List<Exercise>() it also throws an error

    Data I get from my Database (shortened)

    List of:

    [{name: number 1, id: 56, exercise: [{"index":1,"weightGoal":[15,16,17]}, {"index":3,"weightGoal":[15,16,17]}], pause: [{"index":2}]},{"index":4}]}]
    

    What I do with it

    Here I try to go through the list and convert it into a List of PlanModel:

    List<PlanModel> list =
            res.isNotEmpty ? res.map((c) => PlanModel.fromJson(c)).toList() : [];
        return list;
    

    Full model

    PlanModel planModelFromJson(String str) => PlanModel.fromJson(json.decode(str));
    
    String planModelToJson(PlanModel data) => json.encode(data.toJson());
    
    class PlanModel {
      PlanModel({
        this.name,
        this.id,
        this.workoutDays,
        this.pastId,
        this.timesDone,
        this.exercise,
        this.pause,
      });
    
      String name;
      int id;
      List<String> workoutDays;
      int pastId;
      int timesDone;
      List<Exercise> exercise;
      List<Pause> pause;
    
      factory PlanModel.fromJson(Map<String, dynamic> json) => PlanModel(
        name: json["name"],
        id: json["id"],
        workoutDays: List<String>.from(jsonDecode(json["workoutDays"])),
        pastId: json["pastId"],
        timesDone: json["timesDone"],
        exercise: json["Exercise"] != null ? new List<Exercise>.from(json["Exercise"].map((x) => Exercise.fromJson(x))): List<Exercise>(),
        pause: json["Pause"] != null ? new List<Pause>.from(json["Pause"].map((x) => Pause.fromJson(x))): List<Pause>(),
      );
    
      Map<String, dynamic> toJson() => {
        "name": name,
        "id": id,
        "workoutDays": List<dynamic>.from(workoutDays.map((x) => x)),
        "pastId": pastId,
        "timesDone": timesDone,
        "Exercise": List<dynamic>.from(exercise.map((x) => x.toJson())),
        "Pause": List<dynamic>.from(pause.map((x) => x.toJson())),
      };
    
    
    
    }
    
    class Exercise {
      Exercise({
        this.index,
        this.name,
        this.goal,
        this.repGoal,
        this.weightGoal,
        this.timeGoal,
        this.setGoal,
      });
    
      int index;
      String name;
      int goal;
      int repGoal;
      List<int> weightGoal;
      int timeGoal;
      List<String> setGoal;
    
      Exercise.fromJson(dynamic json) {
        // anything that is wrapped around with this [] in json is converted as list
        // anything that is wrapped around with this {} is map
        index = json["index"];
        name = json["name"];
        goal = json["goal"];
        repGoal = json["repGoal"];
        weightGoal = json["weightGoal"] != null ? json["weightGoal"].cast<int>() : [];
        timeGoal = json["timeGoal"];
        setGoal = json["setGoal"] != null ? json["setGoal"].cast<String>() : [];
      }
    
      Map<String, dynamic> toJson() => {
        "index": index,
        "name": name,
        "goal": goal,
        "repGoal": repGoal,
        "weightGoal": List<dynamic>.from(weightGoal.map((x) => x)),
        "timeGoal": timeGoal,
        "setGoal": List<dynamic>.from(setGoal.map((x) => x)),
      };
    }
    
    class Pause {
      Pause({
        this.index,
        this.timeInMilSec,
      });
    
      int index;
      int timeInMilSec;
    
      factory Pause.fromJson(Map<String, dynamic> json) => Pause(
        index: json["index"],
        timeInMilSec: json["timeInMilSec"],
      );
    
      Map<String, dynamic> toJson() => {
        "index": index,
        "timeInMilSec": timeInMilSec,
      };
    }
    
    • Claudio Castro
      Claudio Castro over 3 years
      Im not sure, but I think key are case sensitive. You are using: json["Exercise"] and json["Pause"]
    • m123
      m123 over 3 years
      @ClaudioCastro thanks for your comment, but this is fine, I also initialized both of them uppercase, since there are no variables, rather classses.
    • man of knowledge
      man of knowledge over 3 years
      @M123 can you please give us all the data you get, full version of the PlanModel, and full version of your Exercise so I can test it and make something work from it?
    • m123
      m123 over 3 years
      @manofknowledge here you go
    • Pieter van Loon
      Pieter van Loon over 3 years
      exercise is lowercase in the database but you try to get it using Exercise with an uppercase E
    • man of knowledge
      man of knowledge over 3 years
      I'll get back to you tomorrow it's late here
    • Pieter van Loon
      Pieter van Loon over 3 years
      I mean change it in the fromJson from Exercise to exercise
    • m123
      m123 over 3 years
      @PietervanLoon I already understood what you mean, it may be that this is part of the problem. But if I switch to lower case letters then is: if (snapshot.hasData) {} in "where I read it" false, that means no more data arrives. Thanks anyway
  • m123
    m123 over 3 years
    Thanks for your answer, appreciate it. I tried a bit more around and edited my Question, but the List of exercise I get is empty, that means, if I try to get a value from exercise [0], I get an error
  • man of knowledge
    man of knowledge over 3 years
    I am really happy for you! sorry I was not able to answer sooner.
  • m123
    m123 over 3 years
    @manofknowledge Thank you, and no problem, I just gave you the bounty bc since you dealt with the problem, thanks for that