I have created a code that creates a text field when a button is pushed. i got the problem that if you type something in text field 1 it automaticly is in text field 2 so i cant have 2 diffrent things
I have the following code
int numberOfTextFields = 1;
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
leading: CloseButton(),
actions: buildEditingActions(),
backgroundColor: Colors.red,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
for(int i = 0 ; i < numberOfTextFields ; i )
buildExerciseComplete(),
buildAddMore(),
],
),
),
),
);
with is a simple button and the buildsets() being this:
Widget buildSets() => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: TextStyle(fontSize: 15),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Sets',
),
onFieldSubmitted: (_) => saveForm,
validator: (sets) =>
sets != null && sets.isEmpty ? 'Sets cannot be empty' : null,
controller: setsController,
);
and this is the button:
Widget buildAddMore() => ElevatedButton(
onPressed: () {
setState((){
numberOfTextFields ;
});
},
child: Text('Add new exercise'),
);
The way i store the information is in "sets" and if this was in like PHP i would say sets$numberOfTextFields to give them all a diffrent location to store. Im not quite sure how to do that in flutter and i tried the method with sets${numberOfTextFields}. but i dindt work
My code up here is a bit i a bit simplyfied. My real code looks like this: The problem is that the two diffrent fiels always have the same values Picture of how it looks
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'utils.dart';
import 'event_provider.dart';
class EventEditingPage extends StatefulWidget {
final Event? event;
const EventEditingPage({Key? key, this.event}) : super(key: key);
@override
_EventEditingPageState createState() => _EventEditingPageState();
}
class _EventEditingPageState extends State<EventEditingPage> {
final _formKey = GlobalKey<FormState>();
final setsController = TextEditingController();
@override
void initState() {
super.initState();
final event = widget.event!;
setsController.text = event.Sets;
}
}
@override
void dispose() {
setsController.dispose();
super.dispose();
}
int numberOfTextFields = 1;
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
leading: CloseButton(),
actions: buildEditingActions(),
backgroundColor: Colors.red,
),
body: SingleChildScrollView(
padding: EdgeInsets.all(12),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
for(int i = 0 ; i < numberOfTextFields ; i )
buildExerciseComplete(),
buildAddMore(),
],
),
),
);
List<Widget> buildEditingActions() => [
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
primary: Colors.transparent, shadowColor: Colors.transparent),
onPressed: saveForm,
icon: Icon(Icons.done),
label: Text('Save'),
)
];
Widget buildExerciseComplete() => Container(
padding: EdgeInsets.all(5.0),
decoration: BoxDecoration(
color: Color.fromARGB(255, 255, 200, 200),
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
width: 2.0,
),
),
height: 50,
child: Row(
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(child: buildSets()),
],
),
),
],
),
);
Widget buildSets() => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: TextStyle(fontSize: 15),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Sets',
),
onFieldSubmitted: (_) => saveForm,
validator: (sets) =>
sets != null && sets.isEmpty ? 'Sets cannot be empty' : null,
controller: setsController,
);
Widget buildAddMore() => ElevatedButton(
onPressed: () {
setState((){
numberOfTextFields ;
});
},
child: Text('Add new exercise'),
);
Future saveForm() async {
final isValid = _formKey.currentState!.validate();
if (isValid) {
final event = Event(
Sets: setsController.text);
class Event {
final String Sets;
final Color backgroundColor;
const Event({
required this.Sets,
});
}
CodePudding user response:
Setting the controller: setsController
for every textfield in your loop is the cause of your issue, setting the same TextEditingController for multiple TextField will lead to have the same thing you type in all the textFields that shares the same controller, to solve this issue, you need to initialize a TextEditingController for every TextField
UPDATE:
To set a different controller for each field, you have to create a List<TextEditingController>
and it must be the same size of your numberOfTextFields
, pass the controller or the index to your method:
Widget buildSets(final TextEditingController controller) => TextFormField(
keyboardType: TextInputType.number,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.digitsOnly
],
style: TextStyle(fontSize: 15),
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Sets',
),
onFieldSubmitted: (_) => saveForm,
validator: (sets) =>
sets != null && sets.isEmpty ? 'Sets cannot be empty' : null,
controller: controller,
);
//Calling the method:
for(int i = 0 ; i < numberOfTextFields ; i )
buildSets(myControllers[i]),
CodePudding user response:
The problem is that you are using the same TextEditingController()
with all the Text Fields, you have to create a controller for each one, you can do the following:
Step 1: Remove the currently used TextEditingController
logic.
Step 2: In the screen containing the variable named numberOfTextFields
, define a List of TextEditingController
and start it with a controller inside:
List<TextEditingController> _textEditingControllers = [TextEditingController()];
Step 3: In add more function, when you increment the numberOfTextFields
variable, add a new controller to the list:
onPressed: () {
setState(() {
numberOfTextFields ;
_textEditingControllers.add(TextEditingController());
});
},
Step 4: Inside the loop when you create the Text Fields based on the value of the variable numberOfTextFields
, pass the controller that corresponds the value of the loop counter i
to the widget from the list:
children: [
for(int i = 0 ; i < numberOfTextFields ; i )
buildExerciseComplete(controller: _textEditingControllers[i]),
buildAddMore(),
],
*Note that the TextFormField
is already nested in some widgets, then you have to pass the controller to the widget until you reach the TextFormField
.
Step 5: In the screen where you declared the _textEditingControllers
list, dispose all the controllers in the list in dispose method:
@override
void dispose() {
for (TextEditingController controller in _textEditingControllers)
{
controller.dispose();
}
super.dispose();
}
That's It!
CodePudding user response:
Create separate respective controller for each field.
You can use List<TextEditingController> controllers
to store controllers in it and with each iteration of the loop, you can use controllers.add
method to add a controller with controllers[i].text = '$i'
. And set the controller in textField like this: controller: controllers['i']
.