Search code examples
flutterflutter-form-builder

dynamically adding widgets (FormBuilderTextField) to formBuilder


I'm using flutter_form_builder to create my forms. The user will create his own poll using the form, and he/she will add choices to his/her question as much as needed. I solved the dynamic addition of choices part, but the problem now is; when I create a question with one choice and hit the submit button, the choice, the question and the date gets printed in the console, but if I hit the fab button to create another choice, only the newly created field will print it's content along with the date and the question, and the older field gets disregarded.

How can I get the results of every field gets created dynamically..

Thanks in advance..

Here's my code:-

import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:intl/intl.dart';


class AddPoll extends StatefulWidget {
  @override
  _AddPollState createState() => _AddPollState();
}

class _AddPollState extends State<AddPoll> {

  final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
  List<Widget> choiceFieldList;

  void initState() {
    super.initState();
    choiceFieldList = <Widget>[];
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(title: Text("Create a poll")),
        floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () {
            setState(() {
              choiceFieldList.add(ChoiceField());
            });
          }
        ),
        body: Padding(
          padding: EdgeInsets.all(10.0),
          child: SingleChildScrollView(
            child: Column(
              children: [
                FormBuilder(
                  key: _fbKey,
                  initialValue: {
                    'date': DateTime.now()
                  },
                  autovalidateMode: AutovalidateMode.always,
                  child: Column(
                    children: <Widget>[
                      FormBuilderTextField(
                        attribute: 'question',
                        validators: [FormBuilderValidators.required()],
                        maxLines: null,
                        keyboardType: TextInputType.multiline,
                        decoration: InputDecoration(
                          labelText: "Your Question",
                          border: OutlineInputBorder()
                        )
                      ),
                      Container(
                        padding: EdgeInsets.fromLTRB(0, 30, 0, 20),
                        alignment: Alignment.centerLeft,
                        child: Text(
                          "Choices:-",
                          style: TextStyle(
                            fontSize: 18,
                            fontWeight: FontWeight.bold
                          )
                        )
                      ),
                      ListView.builder(
                        shrinkWrap: true,
                        itemCount: choiceFieldList.length,
                        itemBuilder: (context, index) => choiceFieldList[index],
                      ),
                      Visibility(
                        visible: false,
                        child: FormBuilderDateTimePicker(
                          attribute: "date",
                          inputType: InputType.both,
                          validators: [FormBuilderValidators.required()],
                          format: DateFormat("dd-MM-yyyy 'at' h:mma"),
                          decoration: InputDecoration(labelText: "Date of Poll")
                        )
                      )
                    ]
                  )
                ),
                SizedBox(height: 30.0),
                ButtonBar(
                  alignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    RaisedButton(
                      child: Text("Reset"),
                      onPressed: () {
                        _fbKey.currentState.reset();
                      }
                    ),
                    RaisedButton(
                      child: Text("Submit"),
                      onPressed: () async {
                        _fbKey.currentState.save();
                        print(_fbKey.currentState.value);
                        if (_fbKey.currentState.validate()) {
                          // Loading().show(context);
                          // var date = _fbKey.currentState.value['date'];
                          // var resp = await registerUser(date);
                        }
                      }
                    )
                  ]
                )
              ]
            )
          )
        )
      )
    );
  }
}

class ChoiceField extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return Center(
      child: FormBuilderTextField(
        attribute: 'choice',
        validators: [FormBuilderValidators.required()],
        decoration: InputDecoration(
          labelText: "Enter Choice",
          border: OutlineInputBorder()
        )
      )
    );
  }
}

Solution

  • You can copy paste run full code below
    You need to provide different attribute name
    you can use attributeName: "choice ${choiceFieldList.length}"
    code snippet

    onPressed: () {
              setState(() {
                choiceFieldList.add(ChoiceField(
                  attributeName: "choice ${choiceFieldList.length}",
                ));
              });
            }
    ...     
    class ChoiceField extends StatelessWidget {
      final String attributeName;
      ChoiceField({this.attributeName});
    
      @override
      Widget build(BuildContext context) {
        return Center(
            child: FormBuilderTextField(
                attribute: attributeName,   
    

    output

    I/flutter ( 7497): {date: 2020-10-05 08:54:56.785373, question: q, choice 0: a, choice 1: b}
    

    working demo

    enter image description here

    full code

    import 'package:flutter/material.dart';
    import 'package:flutter_form_builder/flutter_form_builder.dart';
    import 'package:intl/intl.dart';
    
    class AddPoll extends StatefulWidget {
      @override
      _AddPollState createState() => _AddPollState();
    }
    
    class _AddPollState extends State<AddPoll> {
      final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
      List<Widget> choiceFieldList;
    
      void initState() {
        super.initState();
        choiceFieldList = <Widget>[];
      }
    
      @override
      Widget build(BuildContext context) {
        return SafeArea(
            child: Scaffold(
                appBar: AppBar(title: Text("Create a poll")),
                floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
                floatingActionButton: FloatingActionButton(
                    child: Icon(Icons.add),
                    onPressed: () {
                      setState(() {
                        choiceFieldList.add(ChoiceField(
                          attributeName: "choice ${choiceFieldList.length}",
                        ));
                      });
                    }),
                body: Padding(
                    padding: EdgeInsets.all(10.0),
                    child: SingleChildScrollView(
                        child: Column(children: [
                      FormBuilder(
                          key: _fbKey,
                          initialValue: {'date': DateTime.now()},
                          autovalidateMode: AutovalidateMode.always,
                          child: Column(children: <Widget>[
                            FormBuilderTextField(
                                attribute: 'question',
                                validators: [FormBuilderValidators.required()],
                                maxLines: null,
                                keyboardType: TextInputType.multiline,
                                decoration: InputDecoration(
                                    labelText: "Your Question",
                                    border: OutlineInputBorder())),
                            Container(
                                padding: EdgeInsets.fromLTRB(0, 30, 0, 20),
                                alignment: Alignment.centerLeft,
                                child: Text("Choices:-",
                                    style: TextStyle(
                                        fontSize: 18,
                                        fontWeight: FontWeight.bold))),
                            ListView.builder(
                              shrinkWrap: true,
                              itemCount: choiceFieldList.length,
                              itemBuilder: (context, index) =>
                                  choiceFieldList[index],
                            ),
                            Visibility(
                                visible: false,
                                child: FormBuilderDateTimePicker(
                                    attribute: "date",
                                    inputType: InputType.both,
                                    validators: [FormBuilderValidators.required()],
                                    format: DateFormat("dd-MM-yyyy 'at' h:mma"),
                                    decoration:
                                        InputDecoration(labelText: "Date of Poll")))
                          ])),
                      SizedBox(height: 30.0),
                      ButtonBar(
                          alignment: MainAxisAlignment.spaceEvenly,
                          children: <Widget>[
                            RaisedButton(
                                child: Text("Reset"),
                                onPressed: () {
                                  _fbKey.currentState.reset();
                                }),
                            RaisedButton(
                                child: Text("Submit"),
                                onPressed: () async {
                                  _fbKey.currentState.save();
                                  print(_fbKey.currentState.value);
                                  if (_fbKey.currentState.validate()) {
                                    // Loading().show(context);
                                    // var date = _fbKey.currentState.value['date'];
                                    // var resp = await registerUser(date);
                                  }
                                })
                          ])
                    ])))));
      }
    }
    
    class ChoiceField extends StatelessWidget {
      final String attributeName;
      ChoiceField({this.attributeName});
    
      @override
      Widget build(BuildContext context) {
        return Center(
            child: FormBuilderTextField(
                attribute: attributeName,
                validators: [FormBuilderValidators.required()],
                decoration: InputDecoration(
                    labelText: "Enter Choice", border: OutlineInputBorder())));
      }
    }
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: AddPoll(),
        );
      }
    }