Using POST method to return form responses in Flutter as an array inside of an object

Viewed 17

I am a beginner to Flutter and I have a mobile app that is collecting input data in a form. The form itself is dynamic and the fields are fetched using the specific activity id. This is the code for fetching the form:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:mne/Forms/form_model.dart';

import 'package:shared_preferences/shared_preferences.dart';

import '../Network/api.dart';

class FormWidget extends StatefulWidget {
  const FormWidget({Key? key}) : super(key: key);

  @override
  State<FormWidget> createState() => FormWidgetState();
}

class FormWidgetState extends State<FormWidget> {
  // to show error message
  
  _showScaffold(String message) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        content: Text(message, style: const TextStyle(color: Colors.black)),
        duration: const Duration(seconds: 20),
        action: SnackBarAction(
          textColor: Colors.white,
          label: 'Press to go back',
          onPressed: () {
            Navigator.of(context).pop();
          },
        ),
        backgroundColor: Colors.redAccent));
  }

  final List<FormModel> _formfields = [];
  var loading = false;
  var isEmpty = false;

// to fetch form fields 
  Future<Null> _fetchFormFields() async {
    setState(() {
      loading = true;
    });

    WidgetsFlutterBinding.ensureInitialized();
    SharedPreferences localStorage = await SharedPreferences.getInstance();

    var saved = localStorage.getString('activitytask_id');

    var res = await Network().getData('mobile/activity-fields/$saved');

    if (res.statusCode == 200) {
      final data = jsonDecode(res.body);
      final tdata = data['data'];
      if (tdata.length == 0) {
        _showScaffold('There are no fields to display');
      }

      // //getting the length of tdata
      // var length = tdata.length;
      // //converting length to an integer
      // var len = int.parse(length);
      // debugPrint(len.toString());

      var formfieldsJson = tdata;

      setState(() {
        for (Map formfieldJson in formfieldsJson) {
          _formfields.add(FormModel.fromJson(formfieldJson));
        }
        loading = false;
      });
    }
  }

  final TextEditingController _textController = TextEditingController();
  final TextEditingController _numberController2 = TextEditingController();

  @override
  void initState() {
    super.initState();
    _fetchFormFields();
  }


  // to display form fields 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
            color: Colors.white,
            child: loading
                ? const Center(child: CircularProgressIndicator())
                : ListView.builder(
                    itemCount: _formfields.length,
                    itemBuilder: (context, i) {
                      final nDataList = _formfields[i];
                      var response = [nDataList.id];
                      return Form(
                          child: Column(children: [
                        Column(children: [
                          if (nDataList.type == 'text')
                            Column(children: [
                              Container(
                                alignment: Alignment.centerLeft,
                                padding:
                                    const EdgeInsets.only(bottom: 5, left: 6),
                                child: Text('Add a ${nDataList.name}',
                                    style: const TextStyle(
                                        fontSize: 16,
                                        fontWeight: FontWeight.bold)),
                              ),
                              Container(
                                  margin: const EdgeInsets.all(8),
                                  child: TextFormField(
                                    controller: _textController,
                                    onChanged: (value) {
                                      setState(() {
                                        _textController.text = value;
                                      });
                                    },
                                    decoration: InputDecoration(
                                        contentPadding:
                                            const EdgeInsets.all(15),
                                        border: const OutlineInputBorder(),
                                        filled: true,
                                        fillColor: Colors.grey[200],
                                        labelText: nDataList.name),
                                  ))
                            ]),
                          if (nDataList.type == 'number')
                            Column(children: [
                              Container(
                                alignment: Alignment.centerLeft,
                                padding: const EdgeInsets.only(
                                    bottom: 5, left: 6, top: 5),
                                child: Text('Add a ${nDataList.name}',
                                    style: const TextStyle(
                                        fontSize: 16,
                                        fontWeight: FontWeight.bold)),
                              ),
                              Container(
                                  margin: const EdgeInsets.all(8),
                                  child: TextFormField(
                                    onChanged: (value) {
                                      setState(() {
                                        _numberController2.text = value;
                                      });
                                    },
                                    controller: _numberController2,
                                    decoration: InputDecoration(
                                        contentPadding:
                                            const EdgeInsets.all(15),
                                        border: const OutlineInputBorder(),
                                        filled: true,
                                        fillColor: Colors.grey[200],
                                        labelText: nDataList.name),
                                  )),
                            ]),
                        ]),
                      ]));
                    })));
  }
}

This is the GET function I am using:

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';

class Network {
  final String _url = 'http://18.116.46.98:7000/api/';
  // ignore: prefer_typing_uninitialized_variables
  var token;

  _getToken() async {
    SharedPreferences localStorage = await SharedPreferences.getInstance();
    token = jsonDecode(
        localStorage != null ? localStorage.getString('token') : token);
    // token = jsonDecode(localStorage.getString('token'))['token'];
  }

  authData(data, apiUrl) async {
    var fullUrl = _url + apiUrl;
    return await http.post(Uri.parse(fullUrl),
        body: jsonEncode(data), headers: _setHeaders());
  }

// to get all the data
  getData(apiUrl) async {
    var fullUrl = _url + apiUrl;
    await _getToken();
    return await http.get(Uri.parse(fullUrl), headers: _setHeaders());
  }

  _setHeaders() => {
        'Content-type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'Bearer $token'
      };
}

And this is the post method that I am using to return the login data for authentication:

authData(data, apiUrl) async {
    var fullUrl = _url + apiUrl;
    return await http.post(Uri.parse(fullUrl),
        body: jsonEncode(data), headers: _setHeaders());
  }

The backend requires me to return data in the following format:

{
    "activity_responses": [
        {
            "activity_field_id": "23ef235f-1db0-4535-8640-7f5eb8b4972c",
            "value": "started"
        },
        {
            "activity_field_id":"2d632381-c3c4-44ad-8cf2-1185072eda52",
            "value": "This is a note"
        },
        {
            "activity_field_id": "922a5daf-4e1f-4cba-b0ab-b32ed43c9038",
            "value": "5000"
        }
    ]
}

I need to input the specific field id that is part of the data that is returned in the aforementioned _getFormFields() function. In this app, to form fields are tied to the activity and the activity is tied to the task. In order to fetch these, I have been saving the id locally using shared preferences and then getting them and using them in the api url like shown below:

this is the code to get the activity id, where the id is saved locally to a variable 'saved' on clicking the button at the end :

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../Network/api.dart';
import '../Projects/project_widget.dart';
import 'activity_model.dart';

class ActivityWidget extends StatefulWidget {
  const ActivityWidget({Key? key}) : super(key: key);

  @override
  ActivityWidgetState createState() => ActivityWidgetState();
}

class ActivityWidgetState extends State<ActivityWidget> {
  final List<Activity> _activities = [];
  var loading = false;

  Future<Null> _fetchActivities() async {
    setState(() {
      loading = true;
    });
    WidgetsFlutterBinding.ensureInitialized();
    SharedPreferences localStorage = await SharedPreferences.getInstance();
    // ignore: unused_local_variable
    var saved = localStorage.getString('project_id');
    var res = await Network().getData('mobile/project-tasks/$saved');
    if (res.statusCode == 200) {
      final data = jsonDecode(res.body);
      final tdata = data['data'];
      var activitiesJson = tdata;

      setState(() {
        for (Map activityJson in activitiesJson) {
          _activities.add(Activity.fromJson(activityJson));
        }
        loading = false;
      });
    }
  }

  @override
  void initState() {
    super.initState();
    _fetchActivities();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
            color: Colors.white,
            child: loading
                ? const Center(child: CircularProgressIndicator())
                : ListView.builder(
                    itemCount: _activities.length,
                    itemBuilder: (context, i) {
                      final nDataList = _activities[i];
                      return Card(
                          elevation: 5,
                          color: Colors.white,
                          child: Padding(
                              padding: const EdgeInsets.only(
                                top: 32.0,
                                bottom: 22.0,
                                left: 16.0,
                                right: 16.0,
                              ),
                              child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: <Widget>[
                                    Container(
                                        padding:
                                            const EdgeInsets.only(bottom: 5),
                                        child: RichText(
                                            text: TextSpan(children: [
                                          const TextSpan(
                                              text: 'Task Title: ',
                                              style: TextStyle(
                                                  fontSize: 16,
                                                  fontWeight: FontWeight.bold,
                                                  color: Colors.black)),
                                          TextSpan(
                                              text: nDataList.title,
                                              style: const TextStyle(
                                                  fontSize: 14,
                                                  color: Colors.black))
                                        ]))),
                                    RichText(
                                        text: TextSpan(children: [
                                      const TextSpan(
                                          text: 'Task Status: ',
                                          style: TextStyle(
                                              fontSize: 16,
                                              fontWeight: FontWeight.bold,
                                              color: Colors.black)),
                                      TextSpan(
                                          text: nDataList.status,
                                          style: const TextStyle(
                                              fontSize: 14,
                                              color: Colors.black))
                                    ])),
                                    Container(
                                        padding: const EdgeInsets.only(top: 15),
                                        alignment: Alignment.bottomRight,
                                        child: ElevatedButton(
                                            style: ButtonStyle(
                                                backgroundColor:
                                                    MaterialStateProperty.all<
                                                            Color>(
                                                        const Color.fromRGBO(
                                                            226, 147, 21, 1))),
                                            onPressed: () async {
                                              SharedPreferences localStorage =
                                                  await SharedPreferences
                                                      .getInstance();
                                              localStorage.setString(
                                                  'activity_id', nDataList.id);
                                              // ignore: use_build_context_synchronously
                                              Navigator.pushNamed(
                                                  context, 'activitytasks');
                                            },
                                            child: const Text(
                                              'See Activities',
                                              style: TextStyle(
                                                  color: Colors.black),
                                            )))
                                  ])));
                    })));
  }
}

The value saved in 'saved' is then referenced in the api url of the widget that is used to fetch and display the activity, like this:

 WidgetsFlutterBinding.ensureInitialized();
    SharedPreferences localStorage = await SharedPreferences.getInstance();
    var saved = localStorage.getString('activity_id');
    var res = await Network().getData('mobile/task-activities/$saved');

Back to the question: I have tried to save the specific activity_field_id locally like in the examples above, but I do not know how to return it. Is there a way I can structure my data so that it can send the form responses as an object that holds an array for the corresponding field_id and response? I have also tried to use form field text controllers to save the value itself and then post it but it is not saving the values or posting them. Any help is appreciated.

0 Answers
Related