'flutter create dynamic TextField when button click
Here is my requirement, when I click the Add button, dynamically new cards with three TextFields should be generated, and how to assign each TextField with dynamically created TextEditingControllers> or is there any other way to take value from TextFields?
final name1 = new TextField(
controller: name1Controller,
decoration: InputDecoration(
labelText: 'Full Name', border: OutlineInputBorder()));
final age1 = new TextField(
controller: age1Controler,
keyboardType: TextInputType.number,
decoration:
InputDecoration(labelText: 'Age', border: OutlineInputBorder()));
final studyjob1 = new TextField(
controller: study1Controller,
decoration: InputDecoration(
labelText: 'Study / Job', border: OutlineInputBorder()));
final person1Card = new Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: Padding(
padding: EdgeInsets.only(top: 2.0, left: 6.0, right: 6.0, bottom: 2.0),
child: Column(
children: <Widget>[
Text('Person 1'),
SizedBox(height: 3.0),
name1,
SizedBox(height: 10.0),
age1,
SizedBox(height: 10.0),
studyjob1,
SizedBox(height: 10.0),
],
),
),
);
return Scaffold(
appBar: AppBar(
title: Text('New Entry'),
),
body: SingleChildScrollView(
child: Container(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
children: <Widget>[
person1Card,
SizedBox(
height: 10.0,
),
saveButton
],
),
),
),
),
))
Solution 1:[1]
You can use a List for your controllers.
For example:
class PersonControllers {
final TextEditingController name;
final TextEditingController age;
final TextEditingController job;
PersonControllers(this.name, this.age, this.job);
}
Then in your widget
final List<PersonControllers> personControllers = List<PersonControllers>();
In your initState
personControllers.add(PersonController(TextEditingController(),TextEditingController(),TextEditingController());
Create a buildCard method:
Widget buildCard(PersonControllers controllers){
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: Padding(
padding: EdgeInsets.only(top: 2.0, left: 6.0, right: 6.0, bottom: 2.0),
child: Column(
children: <Widget>[
Text('Person 1'),
SizedBox(height: 3.0),
_buildNameField(controllers.name),
SizedBox(height: 10.0),
_buildAgeField(controllers.age),
SizedBox(height: 10.0),
_buildJobField(controllers.job),
SizedBox(height: 10.0),
],
),
),
);
}
Finally in your build method:
return Scaffold(
appBar: AppBar(
title: Text('New Entry'),
),
body: SingleChildScrollView(
child: Container(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
children: <Widget>[
...personControllers.map((personController) => _buildCard(personController),
SizedBox(
height: 10.0,
),
RaisedButton(
child: Text("Add"),
onPressed: (){
setState((){
personControllers.add(PersonController(
TextEditingController(),
TextEditingController(),
TextEditingController()
});
);
}
),
],
),
),
),
),
))
Solution 2:[2]
if you want remove the form also please look at this code may be it is help full for someone
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
@override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
var nameTECs = <int, TextEditingController>{};
var mailTECs = <int, TextEditingController>{};
List<Entry> entries = [];
var item = <int, Widget>{};
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
@override
void didChangeDependencies() {
super.didChangeDependencies();
item.addAll({0: newMethod(context, 0)});
}
ondDone() {
entries.clear();
print(nameTECs.keys.last);
for (int i = 0; i <= nameTECs.keys.last; i++) {
var name = nameTECs[i]?.value.text;
var mail = mailTECs[i]?.value.text;
// print(mailTECs[i]?.value.text);
if (name != null && mail != null) {
entries.add(Entry(name, mail));
}
}
print(entries);
for (int a = 0; a < entries.length; a++) {
print(entries[a].name);
print(entries[a].email);
}
}
newMethod(
BuildContext context,
int index,
) {
var nameController = TextEditingController();
var mailController = TextEditingController();
nameTECs.addAll({index: nameController});
mailTECs.addAll({index: mailController});
return Column(
children: [
Text(index.toString()),
TextFormField(
controller: nameController,
validator: (value) {
return value!.isEmpty ? 'Enter some text' : null;
},
textFieldType: TextFieldType.NAME,
),
TextFormField(
controller: mailController,
validator: (value) {},
// controller: nameCount,
textFieldType: TextFieldType.NAME,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
FlatButton(
onTap: () {
item.addAll({item.keys.last+1: newMethod(context, item.keys.last + 1)});
setState(() {});
// }
},
child: Text('Add'),
),
FlatButton(
onTap: () {
setState(() {
item.removeWhere((key, value) => key == index);
nameTECs.removeWhere((key, value) => key == index);
mailTECs.removeWhere((key, value) => key == index);
});
},
child: Text('Remove'),
),
],
),
],
);
}
@override
Widget build(BuildContext context) {
print('build');
return Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: [
ListView.builder(
shrinkWrap: true,
physics: ScrollPhysics(),
itemCount: item.length,
itemBuilder: (context, index) {
return item.values.elementAt(index);
}),
// for (int i = 0; i < widgeta.length; i++) widgeta[i],
AppButton(
onTap: () {
if (_formKey.currentState!.validate()) {
ondDone();
// _formKey.currentState!.save();
setState(() {});
}
},
color: appPrimaryColor,
child: Text('save'),
),
Center(
child: Text('Test', textDirection: TextDirection.rtl),
),
],
),
),
),
);
}
}
class Entry {
final String? name;
final String? email;
Entry(
this.name,
this.email,
);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Pyth0nGh057 |
| Solution 2 | Akbar Masterpadi |


