dynamically adding widgets (FormBuilderTextField) to formBuilder

3.3k views Asked by At

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()
        )
      )
    );
  }
}
1

There are 1 answers

1
chunhunghan On BEST ANSWER

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(),
    );
  }
}