flutterdartdart-pubflutter-design

Flutter giving null TextEditingController.text when mapped through an object list


I want to make an object list that will contain all the fields for a form and then map all the Object from the list as form field widget and then display then grab all the input of the user in console

Custom Object that I created this will contain the name of the label and variable of TextEditingController that stores the input value

class custom_formObject {
  late String FO_text;
  late TextEditingController fo_controller = TextEditingController();
  custom_formObject({
      required this.FO_text,

    });
}

The class where I want to use this

class _MyHomePageState extends State<MyHomePage> {
  TextEditingController check_controller = TextEditingController();

  List<custom_formObject> formFieldList=[
    custom_formObject(
      FO_text: "Email",
    ),
    custom_formObject(
      FO_text: "UserName",
    ),
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.primary,
      appBar: AppBar(
        title: Text(widget.title),
        elevation: 0,
      ),
      body: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          children: [
            Column(
              children: [
                CustomFormField(cffText: "Email", cff_contorller: check_controller)
              ],
            ),
            Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: formFieldList.map((field) => CustomFormField(cffText: field.FO_text, cff_contorller: field.fo_controller,)).toList(),
            ),
            Column(
              children: [
                ElevatedButton(
                  onPressed: (){
                    print(formFieldList.map((field){
                      field.fo_controller.text.toString();
                    })
                    );
                  },
                  child : Text("Form Field with Text Output")
                ),
                ElevatedButton(

                onPressed: (){
                    print(check_controller.text);
                    },
                      child:  const Text(
                      "Simple form Field",


                    ),
                    )
              ],
            )
          ],
        ),

      ),
      floatingActionButton: FloatingActionButton(
        onPressed:(){

        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

My Custom Form field that is just returning a widget

class CustomFormField extends StatefulWidget {
  final String cffText;
  // String cffValue;
  var  cff_contorller = TextEditingController();

   CustomFormField(
      { Key? key,
        required this.cffText,
        // required this.cffValue,
        required this.cff_contorller
      }
      ) : super(key: key);

  @override
  State<CustomFormField> createState() => _CustomFormFieldState();
}

class _CustomFormFieldState extends State<CustomFormField> {

  late String newValue="";
  @override
  void initState(){
    super.initState();
    widget.cff_contorller.addListener(() => setState(() {

    }));
    setState(() {
      // widget.cffValue=newValue;
    });
  }
  @override
  Widget build(BuildContext context) {

    return Container(
      padding: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),
      child: TextFormField(
        keyboardType: TextInputType.emailAddress, // this will be passed down
        textInputAction: TextInputAction.done,
        // styling begins Here
        style: TextStyle(color: Theme.of(context).colorScheme.onPrimaryContainer),
        decoration: InputDecoration(
          // errorText: "",
          // errorStyle: TextStyle(
          //   color:Theme.of(context).colorScheme.errorContainer
          // ),
          labelText: widget.cffText,// this will be passed down
          // hintText: "This will be passed an on check whether is enabled or not",
          // prefixIcon: Icon(Icons.mail),// this will be passed on with check whether enabled or not
           suffixIcon:widget.cff_contorller.text.isEmpty
            ?Container(width: 0,)
            :IconButton(
             icon: const Icon(Icons.close),
             onPressed: ()=>widget.cff_contorller.clear(),
             color: Theme.of(context).colorScheme.onPrimary,
             iconSize: 14.0,
           ),
          labelStyle:  TextStyle(
            color: Theme.of(context).colorScheme.secondary,
          ),
          enabledBorder:  OutlineInputBorder(
              borderRadius:const BorderRadius.all(
                Radius.circular(10.0),
              ),
              borderSide:  BorderSide(color: Theme.of(context).colorScheme.secondary, width: 0.0),
            ),

          disabledBorder: OutlineInputBorder(
            borderRadius:const BorderRadius.all(
              Radius.circular(10.0),
            ),
            borderSide:  BorderSide(color: Theme.of(context).colorScheme.outline, width: 0.0),
          ),

            focusedBorder:  OutlineInputBorder(
              borderRadius: const BorderRadius.all(
                Radius.circular(10.0),
              ),
              borderSide:  BorderSide(color: Theme.of(context).colorScheme.secondary, width: 1.0),
            ),

          errorBorder: OutlineInputBorder(
            borderRadius: const BorderRadius.all(
              Radius.circular(10.0),
            ),
            borderSide:  BorderSide(color: Theme.of(context).colorScheme.error, width: 0.0),
          ),
          focusedErrorBorder: OutlineInputBorder(
            borderRadius: const BorderRadius.all(
              Radius.circular(10.0),
            ),
            borderSide:  BorderSide(color: Theme.of(context).colorScheme.error, width: 1.0),
          ),
          // styling Ends Here

        ),

          // Functionality Begins here

          controller: widget.cff_contorller,
          onChanged: (value)=>setState(() {
           newValue=value;
          }),

          // Functionality Ends here


      ),
    );
  }




}

Solution

  • There are some modification on the snippet you can run ,compare and test.

    
    void main() => runApp(MaterialApp(home: MyHomePage()));
    
    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key});
    
      @override
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      List<custom_formObject> formFieldList = [
        custom_formObject(
          FO_text: "Email",
        ),
        custom_formObject(
          FO_text: "UserName",
        ),
      ];
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          floatingActionButton: FloatingActionButton(onPressed: () {
            formFieldList.add(custom_formObject(
              FO_text: "random",
            ));
            setState(() {});
          }),
          body: Padding(
            padding: const EdgeInsets.all(20.0),
            child: Column(
              children: [
                Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: formFieldList
                      .map((field) => CustomFormField(
                            cffText: field.FO_text,
                            cff_contorller: field.fo_controller,
                          ))
                      .toList(),
                ),
                Column(
                  children: [
                    ElevatedButton(
                        onPressed: () {
                          formFieldList.forEach((element) {
                            print(element.fo_controller.text);
                          });
                        },
                        child: Text("Form Field with Text Output")),
                  ],
                )
              ],
            ),
          ),
        );
      }
    }
    
    class CustomFormField extends StatefulWidget {
      final String cffText;
      // String cffValue;
      final TextEditingController cff_contorller;
    
      const CustomFormField({
        Key? key,
        required this.cffText,
        required this.cff_contorller,
      }) : super(key: key);
    
      @override
      State<CustomFormField> createState() => _CustomFormFieldState();
    }
    
    class _CustomFormFieldState extends State<CustomFormField> {
      @override
      Widget build(BuildContext context) {
        return Container(
          child: TextFormField(
            controller: widget.cff_contorller,
          ),
        );
      }
    }
    
    class custom_formObject {
      late String FO_text;
      late TextEditingController fo_controller =
          TextEditingController.fromValue(TextEditingValue(text: FO_text));
      custom_formObject({
        required this.FO_text,
      });
    }