I have a Posts screen where list of posts are displayed. I want to add a textformfield at the bottom area of each post so that users can enter their comments on particular post. As we know that we cannot create a TextEditingController for multiple textformfields.
How can I create, show and use textformfield with the each post for entering users comments?
I am sure there are multiple ways to do this, but here is one fairly simple approach.
Create a Map where the key is a TextFormField and the value is a TextEditingController.
Map<TextFormField, TextEditingController> fields = new Map<TextFormField, TextEditingController>();
Create a new controller and text field for each post and add them to the Map.
fields[text] = controller;
When you want to get the values, you can pass the text field into a method that gets the controller for that field from the Map.
Here is a very basic example of how this can work:
import 'package:flutter/material.dart';
class DynamicTextFieldsWithControllers extends StatefulWidget {
#override
State<StatefulWidget> createState() => DynamicTextFieldsWithControllersState();
}
class DynamicTextFieldsWithControllersState extends State<DynamicTextFieldsWithControllers> {
Map<TextFormField, TextEditingController> fields = new Map<TextFormField, TextEditingController>();
#override
Widget build(BuildContext context) {
List<Widget> widgets = [];
for(int i = 0; i < 5; i++) {
TextEditingController controller = new TextEditingController();
TextFormField text = TextFormField(
controller: controller,
);
fields[text] = controller;
widgets.add(Container(
margin: EdgeInsets.symmetric(horizontal: 8.0, vertical: 15.0),
child: Column(children: [
text,
FlatButton(
color: Colors.blue,
child: Text("Submit", style: TextStyle(color: Colors.white)),
onPressed: () {
getTextValue(text);
},
)
],)
));
}
return Scaffold(
body: Column(children: widgets),
);
}
getTextValue(TextFormField text) {
TextEditingController controller = fields[text];
String value = controller.text;
print(value);
return value;
}
}
Related
How to stick validation text inside TextFormField. By default it goes below
the text field
I want like this
But it shows like this
I have looked in various sources, but did not find a suitable answer
is there any way to show the validation text inside the textbox
You can update text from TextEditingController if validation fails for a certain text field and also can remove text from controller in "onTap" property.
TextEditingController _passwordController = TextEditingController();
if(condition)
{
//success call
}
else
{
setState((){
_passwordController.text="Password Does not match
});
}
you should validate your form in the Following way
class MyForm extends StatefulWidget {
#override
MyFormState createState() {
return MyFormState();
}
}
// Create a corresponding State class.
// This class holds data related to the form.
class MyFormState extends State<MyForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
//
// Note: This is a GlobalKey<FormState>,
// not a GlobalKey<MyFormState>.
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
// The validator receives the text that the user has entered.
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
// sendData();
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Processing Data')));
}
},
child: Text('Submit'),
),
),
],
),
);
}
}
Currently, when a user fills in a TextField the text is lost if they navigate away and then return. How can I get the text to stay in the field upon their return?
Here's the stateful widget I'm using;
class _EditPageState extends State<EditPage> {
final _formKey = GlobalKey<FormState>();
String audiotitle;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
key: _formKey,
child: Container(
child: TextField(
decoration: new InputDecoration(
hintText: widget.oldaudiotitle,
),
keyboardType: TextInputType.text,
onChanged: (titleText) {
setState(() {
this.audiotitle = titleText;
});
},
),
),
),
);
}
}
What am I doing wrong here?
you have two ways :
store the Data of the text field and set the data in init method
(use sharedpreferences or any other database as per your requirements)
TextEditingController controller = TextEditingController();
#override
void initState() {
// TODO: implement initState
// retrive the Data
if(data != null) {
controller = new TextEditingController(text: data);
}
}
or if the first screen is navigating in the second Screen than just pop that screen
Navigator.pop(context);
This is my screen with TextField and Button. When someone clicks on show button, I want it to show the name below the button as shown in below picture.
Code below:
class Demo extends StatefulWidget {
#override
_DemoState createState() => _DemoState();
}
class _DemoState extends State<Demo> {
final name = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: [
Row(
children: [
Text(
'Name'
),
TextField(
controller: name,
)
],
),
RaisedButton(
onPressed: (){
},
child: Text('Show'),
)
],
),
),
);
}
}
This can be a basic example for your question. The UI is not exactly what you've shown above
class Question extends StatefulWidget {
Question({Key key}) : super(key: key);
#override
_QuestionState createState() => _QuestionState();
}
class _QuestionState extends State<Question> {
String text = '';
bool shouldDisplay = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
Center(
child: TextField(
onChanged: (value) {
setState(() {
text = value;
});
},
),
),
FlatButton(onPressed: () {
setState(() {
shouldDisplay = !shouldDisplay;
});
}, child: Text('Submit')),
shouldDisplay ? Text(text) : Spacer()
],
);
}
}
Hope this helps.
Initialize two variables. One for a TextEditingController and one for the text value.
TextEditingController controller = TextEditingController();
String display = '';
Give your TextField a controller.
TextField(controller:controller);
In your button, set onPressed to change display text to the controller text.
FlatButton(
child: Text("Show"),
onPressed()=> setState((){display = controller.text;});
),
Then where you want to show the text, set the text string to display.
Text(display);
I would advice you to learn the basics of flutter first before asking these kinds of questions. This can be simply achieved through using TextEditingController and setState(). Simply define a controller for your TextField and then call setState() when your button is pressed. Note that you have to be on a StatefulWidget since calling setState() rebuilds the UI.
Create a TextEditingController and string above the #override Widget build:
String displayName="";
final myController = TextEditingController();
Create a TextField and add assign the controller to it:
TextField(
controller: myController,
);
Call setState() on button pressed:
MaterialButton(
child: Text("Show"),
onPressed: (){
setState(() {
displayName=myController.text;
});
})
Display it using a Text widget:
Text(displayName);
Good Luck!
You can find out how to use TextEditingController here: https://flutter.dev/docs/cookbook/forms/retrieve-input
More about widgets here: https://www.youtube.com/playlist?list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG
I am new to flutter and I’m trying to create a counter that begins from a user input and decrement but I can’t get an integer input from text field how can I initialize a user input to be an integer then add it to an int variable
That is quite simple, I will show you an example that you can follow.
Example:
class HomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new HomePageState();
}
}
class HomePageState extends State<HomePage> {
// creating and initilizing a counter variable
int _counter = 0;
TextEditingController _controller = TextEditingController();
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new TextField(
controller: _controller,
decoration: new InputDecoration(labelText: "Enter your number"),
keyboardType: TextInputType.number,
),
FlatButton(
onPressed:(){
_counter = int.parse(_controller.text);
},
child: Text('Press Me!'),
)
],
));
}
}
At first, I created a counter and initialize it with '0' and then I created a controller which I will use for controlling the TextField. After that, I created a TextField widget and passed the _controller to it. I used the controller because I need to fetch data from the TextField so do we. We fetched data from the _controller via _controller.text which returns a string. Although we create the counter as an integer, we can't pass a string to it. So, I changed the data that we fetched from the _controller into an integer using int.parse(_controller.text) and then we passed it to the _counter variable.
Note: I had specified the keyboardType as TextInputType.number because we are dealing with numbers as you mentioned.
I am trying to create a page with more than one TextField widgets in flutter. Number of textfields to display are determined at runtime. while creating those textfields a controller from the controller array is attached to each textfield.
Everything is working as expected. but doen't matter which textfield i click, i always get the callback of all the textfields in a single onChanged function.
Therefore, i am not able to detect that value of which textfield is changed.
Please refer to code for more insight.
In-Short, i just want to know how to get the instance of textfield controller which is currently active.
Could somebody please let me know what i am doing wrong.
Thanks
List<TextEditingController> _controllers = <TextEditingController>[];
int controllersAttached = -1;
#override
Widget build(BuildContext context) {
controllersAttached += 1;
for (int i = 0;i < fibProvider.quesTextList.length;i++) ...<dynamic>[
TextField(
autofocus: false,
cursorColor: const Color(0xFFD8D8D8),
maxLines: 1,
textAlign: TextAlign.center,
controller: _controllers[controllersAttached %fibProvider.numberOfBlanks],
onChanged: (String data) {
// here i can distinguish between the controllers depending upon the text
entered in them. but if there are 3 textfields and the same data is
entered in all the three then this code only returns the first
controller with the matched value.
final int index = _controllers.indexWhere(TextEditingController item) {
return data.compareTo(
item.text.toString()) == 0;
});
},
),
]
}
You can just pass i variable to onChanged callback inside collection-for:
class _MyHomePageState extends State<MyHomePage> {
final int _fields = 10;
List<TextEditingController> controllers;
#override
void initState() {
super.initState();
controllers = List.generate(_fields, (i) => TextEditingController());
}
#override
void dispose() {
controllers.forEach((c) => c.dispose());
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title)
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
for (int i = 0; i < _fields; i++)
TextField(
controller: controllers[i],
onChanged: (value) {
final controller = controllers[i];
print('Current field index is $i and new value is $value');
},
),
],
),
)
);
}
}