How can I build this JSON object in Flutter?

Question

Asked by Irwin on November 17, 2021 (source).

This is the object that I want to send to my server from the Flutter client but I am not able to:

{
    "questions": [
        {
            "question" : "La velocidad de la luz es igual a",
            "solucion1": "300k",
            "solucion2": "250k",
            "solucion3" : "150k",
            "answer" : "300k"
        },
        {
            "question" : "Un numero primo es",
            "solucion1": "Solo puede ser dividido entre 1 y si mismo",
            "solucion2": "Puede ser dividido entre 2",
            "solucion3" : "Tiene raiz cuadrada",
            "answer" : "Solo puede ser dividido entre 1 y si mismo"
        },
        {
            "question" : "Las matematicas son",
            "solucion1": "La ciencia que estudia la historia",
            "solucion2": "La ciencia que estudia el oceano",
            "solucion3" : "La ciencia que estudia la relacion entre los numeros",
            "answer" : "La ciencia que estudia la relacion entre los numeros"
        }
    ]
}

Where "questions" could be N amount. Now let me explain how I am trying to build it. I am using a class to handle the questions as follows:

class Questions {
  String question = '';
  String solucion1 = '';
  String solucion2 = '';
  String solucion3 = '';
  String answer = '';

  Questions(
      {required this.answer,
      required this.question,
      required this.solucion1,
      required this.solucion2,
      required this.solucion3});

  Questions.fromJson(Map<String, dynamic> json) {
    question = json['question'];
    solucion1 = json['solucion1'];
    solucion2 = json['solucion2'];
    solucion3 = json['solucion3'];
    answer = json['answer'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['question'] = this.question;
    data['solucion1'] = this.solucion1;
    data['solucion2'] = this.solucion2;
    data['solucion3'] = this.solucion3;
    data['answer'] = this.answer;
    return data;
  }
}

After this, I am trying to build each question with its 3 solutions and its answer as follows:

class Quiz {
  List<Questions> questions = [];

  Quiz({required this.questions});

  Quiz.fromJson(Map<String, dynamic> json) {
    if (json['questions'] != null) {
      json['questions'].forEach((v) {
        questions.add(new Questions.fromJson(v));
      });
    }
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    if (this.questions != []) {
      data['questions'] = this.questions.map((v) => v.toJson()).toList();
    }
    return data;
  }
}

Each question will ALWAYS contain: 1 question, 3 answers and 1 correct answer.

Now, on my Widget Builder I have 2 buttons, 1 to add a new question and 1 to create the quiz, meaning to send the information to the server.

This is the button I am using to add a new question:

CustomOutlinedButton(
                                onPressed: () {
                                  newQuestion = Questions(
                                      answer: answer,
                                      question: question,
                                      solucion1: solucion1,
                                      solucion2: solucion2,
                                      solucion3: solucion3);
                                  newQuiz = Quiz.fromJson(newQuestion.toJson());
                                  print(newQuiz.questions);

                                  _optiona.clear();
                                  _optionb.clear();
                                  _optionc.clear();
                                  _question.clear();
                                  _answer.clear();
                                },
                                text: 'Agregar Pregunta')

And when I try to print the value of the newQuiz that should have the values from each question it only prints [].

This is the button to send the Quiz to the request method:

CustomOutlinedButton(
                                onPressed: () async {
                                  //print(data);
                                  await createQuiz(
                                      newQuiz.questions, teacherid, subjectid);
                                },
                                text: "Crear Quiz"),

Now below the full Widget Builder code:

Widget build(BuildContext context) {
    Questions newQuestion;
    Quiz newQuiz = new Quiz(questions: []);

    String question = "";
    String solucion1 = "";
    String solucion2 = "";
    String solucion3 = "";
    String answer = "";
    return Scaffold(
      appBar: AppBar(
        title: Text("Crear un nuevo quiz de $subjectName"),
        backgroundColor: Colors.green[700],
      ),
      body: ChangeNotifierProvider(
          create: (_) => LoginFormProvider(),
          child: Builder(builder: (context) {
            var _question = TextEditingController();
            var _optiona = TextEditingController();
            var _optionb = TextEditingController();
            var _optionc = TextEditingController();
            var _answer = TextEditingController();
            final loginFormProvider =
                Provider.of<LoginFormProvider>(context, listen: true);
            return Container(
                color: Colors.grey[100],
                padding: EdgeInsets.symmetric(horizontal: 20),
                child: Center(
                  child: ConstrainedBox(
                    constraints: BoxConstraints(maxHeight: 450),
                    child: Form(
                      key: loginFormProvider.formKey,
                      child: Column(
                        children: [
                          TextFormField(
                            onChanged: (value) => question = value,
                            controller: _question,
                            decoration: buildInputDecoration(
                                hint: 'Pregunta',
                                label: 'Pregunta',
                                icon: Icons.edit),
                          ),
                          SizedBox(
                            height: 10,
                          ),
                          TextFormField(
                            onChanged: (value) => solucion1 = value,
                            controller: _optiona,
                            decoration: buildInputDecoration(
                                hint: 'Opcion A',
                                label: 'Opcion A',
                                icon: Icons.edit),
                          ),
                          SizedBox(
                            height: 10,
                          ),
                          TextFormField(
                            onChanged: (value) => solucion2 = value,
                            controller: _optionb,
                            decoration: buildInputDecoration(
                                hint: 'Opcion B',
                                label: 'Opcion B',
                                icon: Icons.edit),
                          ),
                          SizedBox(
                            height: 10,
                          ),
                          TextFormField(
                            onChanged: (value) => solucion3 = value,
                            controller: _optionc,
                            decoration: buildInputDecoration(
                                hint: 'Opcion C',
                                label: 'Opcion C',
                                icon: Icons.edit),
                          ),
                          SizedBox(
                            height: 10,
                          ),
                          TextFormField(
                            onChanged: (value) => answer = value,
                            controller: _answer,
                            cursorColor: Colors.green,
                            decoration: buildInputDecoration(
                                hint: 'Respuesta',
                                label: 'Respuesta',
                                icon: Icons.edit),
                          ),
                          SizedBox(
                            height: 15,
                          ),
                          Row(children: [
                            CustomOutlinedButton(
                                onPressed: () async {
                                  //print(data);
                                  await createQuiz(
                                      newQuiz.questions, teacherid, subjectid);
                                },
                                text: "Crear Quiz"),
                            SizedBox(
                              width: 20,
                            ),
                            CustomOutlinedButton(
                                onPressed: () {
                                  newQuestion = Questions(
                                      answer: answer,
                                      question: question,
                                      solucion1: solucion1,
                                      solucion2: solucion2,
                                      solucion3: solucion3);
                                  newQuiz = Quiz.fromJson(newQuestion.toJson());
                                  //newQuiz.toJson();
                                  print(newQuiz.questions);

                                  _optiona.clear();
                                  _optionb.clear();
                                  _optionc.clear();
                                  _question.clear();
                                  _answer.clear();
                                },
                                text: 'Agregar Pregunta'),
                          ])
                        ],
                      ),
                    ),
                  ),
                ));
          })),
    );
  }

Any ideas on how to make this happen? I have tried many things but I still get the print as [].

Answer

Question answered by mmcdon20 (source).

This part is not correct:

newQuiz = Quiz.fromJson(newQuestion.toJson());

Think about it, newQuestion.toJson() will give you something like:

{
  "question" : "La velocidad de la luz es igual a",
  "solucion1": "300k",
  "solucion2": "250k",
  "solucion3" : "150k",
  "answer" : "300k"
}

But Quiz.fromJson() expects data to be in a format like this:

{
  "questions": [
    {
      "question" : "La velocidad de la luz es igual a",
      "solucion1": "300k",
      "solucion2": "250k",
      "solucion3" : "150k",
      "answer" : "300k"
    }
  ]
}

Maybe try:

newQuiz = Quiz(questions: [newQuestion, ...newQuiz.questions]);

Or even just this:

newQuiz.questions.add(newQuestion);
DART FLUTTER JSON
SHARE: