Flutter: getx controller not updated when list data changed. How can i make sure with every list added, GetX controller knows that?

Issue

I simply have a form in stepper there are two fields Name and Email. The Add button works fine and add name and email to list as expected. When I click on save, The JSON data is printed with all the data available in the list.

enter image description here

[{"Name":"first language","Email":"first value"},{"Name":"second language","Email":"second value"},{"Name":"third language","Email":"third value"},{"Name":"test","Email":"test"}]

But, when i click on save button at the bottom, The hard coded list is printed and not the data we entered.

enter image description here

The output is the following. I wanted to get all the list data inside JSON. Currently, the following doesn’t have the manually inserted data from list.:

{"User Data":[{"Name":"first language","Email":"first value"},{"Name":"second language","Email":"second value"},{"Name":"third language","Email":"third value"}]}

The code is as below: –

  1. model.dart
    class User {
      String name;
      String email;
    
      User({this.name, this.email});
    
      Map toJson() => {
            'Name': name,
            'Email': email,
          };
    }

class JSONGenerate {
  List<User> userData;

  JSONGenerate([this.userData]);

  Map toJson() {
    List<Map> userData = this.userData != null
        ? this.userData.map((i) => i.toJson()).toList()
        : null;

    return {
      'User Data': userData,
    };
  }
} 
  1. User.dart
class UserMinor extends StatefulWidget {
  @override
  _UserMinorState createState() => _UserMinorState();
}

class _UserMinorState extends State<UserMinor> {
  final form = GlobalKey<FormState>();
  static var _focusNode = new FocusNode();
  // finding same instance if initialized controller
  final controller = Get.find<UserMinorController>();
  @override
  Widget build(BuildContext context) {
    Widget bodyData() => DataTable(
          onSelectAll: (b) {},
          sortColumnIndex: 0,
          sortAscending: true,
          columns: <DataColumn>[
            DataColumn(label: Text("User Name"), tooltip: "User Name"),
            DataColumn(label: Text("User Email"), tooltip: "User Email"),
          ],
          rows: controller.userList // accessing list from Getx controller
              .map(
                (user) => DataRow(
                  cells: [
                    DataCell(
                      Text(user.name),
                    ),
                    DataCell(
                      Text(user.email),
                    ),
                  ],
                ),
              )
              .toList(),
        );

    return Padding(
      padding: EdgeInsets.all(10.0),
      child: Column(
        children: <Widget>[
          Padding(
            padding: EdgeInsets.all(10.0),
            child: Form(
              key: form,
              child: Container(
                child: Column(
                  children: <Widget>[
                    TextFormField(
                      controller: controller.nameController,
                      focusNode: _focusNode,
                      keyboardType: TextInputType.text,
                      autocorrect: false,
                      maxLines: 1,
                      validator: (value) {
                        if (value.isEmpty) {
                          return 'This field is required';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                        labelText: 'Name',
                        hintText: 'Name',
                        labelStyle: new TextStyle(
                            decorationStyle: TextDecorationStyle.solid),
                      ),
                    ),
                    SizedBox(
                      height: 10,
                    ),
                    TextFormField(
                      controller: controller.emailController,
                      keyboardType: TextInputType.text,
                      autocorrect: false,
                      maxLines: 1,
                      validator: (value) {
                        if (value.isEmpty) {
                          return 'This field is required';
                        }
                        return null;
                      },
                      decoration: InputDecoration(
                          labelText: 'Email',
                          hintText: 'Email',
                          labelStyle: new TextStyle(
                              decorationStyle: TextDecorationStyle.solid)),
                    ),
                    SizedBox(
                      height: 10,
                    ),
                    Column(
                      children: <Widget>[
                        Center(
                          child: Row(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Row(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: <Widget>[
                                  TextButton(
                                    child: Text("Add"),
                                    onPressed: () {
                                      if (validate() == true) {
                                        form.currentState.save();
                                        controller.addLanguagetoList(
                                          controller.nameController.text,
                                          controller.emailController.text,
                                        );
                                      }
                                    },
                                  ),
                                  ElevatedButton(
                                      child: Text("Save"),
                                      onPressed: () {
                                        form.currentState.save();
                                        String minorlanguageListJson =
                                            jsonEncode(controller.userList);
                                        print(minorlanguageListJson);
                                      }),
                                ],
                              ),
                            ],
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
              ),
            ),
          ),
          // GetBuilder rebuilds when update() is called
          GetBuilder<UserMinorController>(
            builder: (controller) => bodyData(),
          ),
        ],
      ),
    );
  }

  bool validate() {
    var valid = form.currentState.validate();
    if (valid) form.currentState.save();
    return valid;
  }
}
  1. stepper.dart
class StepperBody extends StatefulWidget {
  @override
  _StepperBodyState createState() => new _StepperBodyState();
}

class _StepperBodyState extends State<StepperBody> {
  int currStep = 0;
  static var _focusNode = new FocusNode();
  GlobalKey<FormState> _formKey = new GlobalKey<FormState>();

  @override
  void initState() {
    super.initState();
    _focusNode.addListener(() {
      setState(() {});
      print('Has focus: $_focusNode.hasFocus');
    });
  }

  @override
  void dispose() {
    _focusNode.dispose();
    super.dispose();
  }

  List<Step> steps = [
    new Step(
      title: const Text('Technical Language Basics'),
      isActive: true,
      state: StepState.indexed,
      content: UserMinor(),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Container(
      child: new Form(
        key: _formKey,
        child: new ListView(
          children: <Widget>[
            new Stepper(
              steps: steps,
              type: StepperType.vertical,
              currentStep: this.currStep,
              onStepContinue: () {
                setState(() {
                  if (currStep < steps.length - 1) {
                    currStep = currStep + 1;
                  } else {
                    currStep = 0;
                  }
                });
              },
              onStepCancel: () {
                setState(() {
                  if (currStep > 0) {
                    currStep = currStep - 1;
                  } else {
                    currStep = 0;
                  }
                });
              },
              onStepTapped: (step) {
                setState(() {
                  currStep = step;
                });
              },
            ),
            new ElevatedButton(
              child: new Text(
                'Save details',
                style: new TextStyle(color: Colors.white),
              ),
              onPressed: () {
                var technicalInfo = UserMinorController().userList;
                JSONGenerate jsonGenerate = JSONGenerate(technicalInfo);
                print(
                  jsonEncode(jsonGenerate),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}
  1. GetX Controller class
    class UserMinorController extends GetxController {
      TextEditingController nameController = TextEditingController();
      TextEditingController emailController = TextEditingController();
      int currentIndex = 0;
    
      List<User> userList = [
        User(name: "first language", email: "first value"),
        User(name: "second language", email: "second value"),
        User(name: "third language", email: "third value"),
      ];
    
    
    
      void addLanguagetoList(name, email) {
        userList.add(User(name: name, email: email));
        update();
      }
    }

Solution

This is the problem here:

var technicalInfo = UserMinorController().userList;

In GetX that you need to "find" the same instance of the controller with Get.find<UserMinorController>(). That finds the same instance that has the actual list that you’re adding to. The way you were doing it was printing out a different instance UserMinorController which is why it was only printing out the hard coded data.

Your onPressed should look like this.

 onPressed: () {
   var technicalInfo = Get.find<UserMinorController>().userList;
   JSONGenerate jsonGenerate = JSONGenerate(technicalInfo);
   print(jsonEncode(jsonGenerate));
}

Answered By – Loren.A

Answer Checked By – David Marino (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.