Flutter - TextFormField, onChanged doesn't appear to be updating value - flutter

I'm having an issue with the use of a TextFormField in Flutter.
The method called in the initial value returns either null or a String depending on whether an add or edit screen is being used respectively.
If it is an edit screen I'd like the String to be the initial value, and the _itemName to be the initial value if it is not changed, or the new onChanged value if it is.
Below shows two of many attempts that I've made that have presented different problems.
In this case if the user does not edit the text the _itemName ends up being null or a zero length string (I can't remember exactly which one it is):
TextFormField(
initialValue: controller.initialNameValue(),
onChanged: (val) {
setState(() => _itemName = val);
}),
In this case the onChanged method does not update the _itemName and it remains at its initial value:
TextFormField(
initialValue: _itemName = controller.initialNameValue(),
onChanged: (val) {
setState(() => _itemName = val);
}),
The _itemName is then used in an add or edit method where it is passed as a parameter into a setter for a class.
How would I go about ensuring the _itemName remains as its initial value until it's changed, and then when it is changed it updates to the new value? Thanks

After some trial and error I've realised the way of overcoming this problem seems to be to introduce:
#override
void initState() {
super.initState();
_itemName = controller.initialNameValue();
}
And then change the TextFormField to:
TextFormField(
onChanged: (val) {
setState(() => _itemName = val);
},
initialValue: controller.initialNameValue(),
);
The main reason for not introducing a separate controller here was due to the fact I had multiple form fields within the widget I was building, and this created further confusion.
The above approach appears to have solved the issues that I faced, although I understand it may not be the cleanest approach to this.

Related

Flutter Can we use ontap and onchanged property simultaneously on the single TextField?

return TextField(
// something
onTap: () {
// something something
},
onChanged: (value) {
// some if else nesteing
},
)
This is my code I want to know if we can use onTap and onChange on the same TextField.
The short answer is Yes. According to the documentation,
onChanged → ValueChanged<String>?
Called when the user initiates a change to the TextField's value: when they have inserted or deleted text. [...]
onTap → GestureTapCallback?
Called for each distinct tap except for every second tap of a double tap. [...]
They both perform completely different functions on a TextField widget.
https://api.flutter.dev/flutter/material/TextField-class.html
Updated to reflect necessity from the comment section
If you want to do something after the user is done typing, I would recommend using a delay / Debouncer. Like https://gist.github.com/venkatd/7125882a8e86d80000ea4c2da2c2a8ad
final _debouncer = Debouncer(delay: const Duration(seconds: 1));
TextField(
onChanged: (_value) {
_debouncer(() {
setState(() {
print(_value);
});
});
},
);

How to write data in firebase cloud firestore with data type using flutter

When saving data to the Firebase database I want every data to be saved according to its data type. But my all data is stored in String. How can I do it in flutter... like Amount will be int, Through will be String
[
here is my function
sandDataToDB() async {
CollectionReference _collectionReferance =
FirebaseFirestore.instance.collection("Use-of-fund");
return _collectionReferance
.doc()
.set({
"Details of Sector": _DetailsofSectorController.text,
"Through": _ThroughController.text,
"Amount": _AmountController.text,
"Date": _DateController.text,
})
.then((value) => dialog())
.catchError((error) => Fluttertoast.showToast(msg: "something wrong"));
}
here is all code
customAdminTextField(
"Details of Sector", _DetailsofSectorController),
customAdminTextField("Through", _ThroughController),
customAdminTextField("Amount", _AmountController),
customAdminTextField("Date", _DateController),
const SizedBox(
height: 10,
),
customSubmitButton("Submit ", () {
sandDataToDB();
})
You have to parse your data. An example for an integer:
...
"Amount": int.parse(_AmountController.text),
...
Here you can find the supported data types.
According to your question, you might be using the controller in TextFormField, you can get the value of the TextFormField.
This widget covers a TextField widget in a FormField for convenience.
It is not necessary to have a Form ancestor. The Form merely simplifies the process of saving, resetting, or validating numerous fields at the same time. To use without a Form, supply a GlobalKey to the constructor and save or reset the form field with GlobalKey.currentState.
TextEditingController.text defines the initialValue when a controller is defined. A controller should be given if this FormField is part of a scrolling container that generates its children lazily, such as a ListView or a CustomScrollView.
A stateful widget ancestor of the scrolling container should handle the controller's lifetime.
Example code:
TextFormField(
decoration: const InputDecoration(
icon: Icon(Icons.person),
hintText: 'What do people call you?',
labelText: 'Name *',
),
onSaved: (String? value) {
// This optional block of code can be used to run
// code when the user saves the form.
},
validator: (String? value) {
return (value != null && value.contains('#')) ? 'Do not use the # char.' : null;
},
)
You can also use the onSubmitted parameter in TextFormField. Like: onSubmitted: (String value)
Additionally, you can use something like this in the following code:
_formKey.currentState.save(); calls the onSaved() on each textFormField item, which gives all the fields a value and allows you to utilize them as needed.

Flutter - how do you update the value of textfield without reopening the widget?

I have multiple TextFormField, all have their own value from a file.
My problem:
-when I change the value of the TextFormField, it changes the value of it's own parameter, but it only changes the other TextFormField(based on the same parameter) when I reopen that page.
I tried use setState, but I don't know what parameter should it have.
How should I use setState / what would be a better option?
This is how I change the values:
onChanged: (value) =>
{ class.data.minimum = int.parse(value),
setState(() {
class.data.minimum=int.parse(value);
})
},
by default for text you can use ValueKey, but in your case use globalKey

Flutter dropdownButton setState on change not updating dropdown text after selection to show selected item

I created a dropdownButton to allow users to select from a dropdown list which will be populated from an API. For now I am populating using a list I created.
Currently the button is displaying the items from my list but after a selection has been made the list doesnt show the selected item and still shows the hint text. What I would like to happen is after a selection has been made then the dropdownButton shows the item that was selected instead of the hint text.
in the onChanged method I added a setState in hopes of updating the _selectedValue variable to the value that was selected and displaying it in the dropdownButton.
I also added a print statement in my setState method and that does trigger and show me the value within the value variable.
Here is my code.
List<DropdownMenuItem<int>> listItems = [DropdownMenuItem(child: Text("2016"), value: 2016,), DropdownMenuItem(child: Text("2021"), value: 2021,)];
int _selectedValue;
body: DropdownButton(
value: _selectedValue,
items: listItems,
hint: Text("Select Year"),
onChanged: (int value){
setState(() {
_selectedValue = value;
print(value);
});
},
),
Your code is fine, but the problem is maybe you are initializing the _selectedValue inside the build() method. So that whenever you call set state the widget rebuilds and initialize again with the default value.
int _selectedValue;
#override
Widget build(BuildContext context) {
return DropdownButton(
value: _selectedValue,
items: listItems,
hint: Text("Select Year"),
onChanged: (int value){
setState(() {
_selectedValue = value;
print(value);
});
},
),
In case anyone else is having this issue, I had the same issue and it was driving me nuts and I was using setState() appropriately etc., It was 100% where I was defining the "initialValue" property.
I was defining it right inside the build method. That did not work, even though I had the same setup in a sister module and it indeed did work. Not sure why that is.
Once I changed the definition of that variable to the state class, it worked like a charm. Hope it saves some, some cycles.

Flutter: Unable to update variable state

In my application, there is a section to add payment. To add a payment, admin will:
select a user
enter amount
select from date
select to date
And save it.
Goal: I want to update from date dynamically, based on previous date.
Example Case:
we added first payment of a user, from 1st June 2019 to 1st September 2019
when we try to make second payment, when the customer is selected; I want to get last payment to date as from date, populated automatically. (to date from db to from date in form)
It can't be done at initialization, because the date varies for each user, so we can do it upon user selection.
What I've done:
I've almost done everything, but having issue in updating field value.
I've done these steps:
created a function which executes, when the user is selected
function queries db, and pulls last payment detail
and returns to date field value of previous payment
the from date field value is set inside the same function like this:
setState(() {
_fromDate = DateTime.parse(toDate);
});
Problem:
Printing _fromDate inside setState function prints correct value, but it's null outside.
Please tell me, how can I update value properly and get rid off this issue?
Update: The Widget code is below: (the state is set as mentioned above, after getting data from db)
DateTimeField(
onSaved: (val) => setState(() => _fromDate = val),
keyboardType: TextInputType.datetime,
onChanged: (DateTime newValue) {
setState(() {
_fromDate = newValue;
});
},
onShowPicker: (context, currentValue) {
return showDatePicker(
context: context,
firstDate: DateTime.now(),
initialDate: currentValue ?? DateTime.now(),
);
},
);
Use TextEditingController class to handle run time text field changes.
Whenever the user modifies a text field with an associated TextEditingController, the text field updates value and the controller notifies its listeners. Listeners can then read the text and selection properties to learn what the user has typed or how the selection has been updated.
The process is pretty simple, just follow these steps:
Create controller:
TextEditingController _fromDateController = new TextEditingController();
Assign it to your DateTimeField like this:
DateTimeField(
...
controller: _fromDateController,
);
Update onSaved method of your field:
DateTimeField(
...
onSaved: (val) => _fromDateController.text = val.toString(),
);
Update controller when you get data from db:
setState(() {
_fromDateController.text = toDate;
});
Lastly, don't forget to dispose it:
Remember to dispose of the TextEditingController when it is no longer needed. This will ensure we discard any resources used by the object.
#override
void dispose() {
_fromDateController.dispose();
...
super.dispose();
}
Hope it helps!