Flutter: Unable to update variable state - flutter

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!

Related

How get more than 2 inputs from user and perform calculation and display the result in flutter application?

How to get more than 2 inputs from user and perform calculation and display the result in flutter application without using any library.
I wanna create a calculator without using any library, and want to do calculations like multiply, add subtract, division 2+6?/3-1 like this. I know how to do calculation for 2 digits but don't know how to do for more inputs. Should i use regex for this??if yes then how.
God to know:
You need TextFormField. In order to show results of the calculations to the client immediately, you should use setState method on TextFormField property onChanged.
TextEditingController _controllerFrom = TextEditingController();
String? valueFrom;
Example:
TextFormField(
onTap: () {},
controller: _controllerFrom ,
onChanged: (String value) {
if (value.isNotEmpty) {
setState(() {
valueFrom = value;
});
}
}
Also, you must dispose this controller when leaving this page on this way:
void dispose() {
// clean up the controller when the widget is disposed
_controllerFrom.dispose();
super.dispose();}

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

Refreshing Dialog In Flutter with Bloc

So I'm trying to pick a date with a DatePicker package from inside a showDialog using Bloc.
Here's the code that shows the Dialog:
onPressed: () {
showDialog(
context: context,
barrierDismissible: true,
child: _buildEditDialog(context, arguments),
);
},
And here's the Dialog's content:
void _openCalendarPicker(BuildContext context, SearchHotelArguments arguments) async {
final DateTime dateTimeNow = DateTime.now();
final List<DateTime> picked = await DateRagePicker.showDatePicker(
context: context,
initialFirstDate: arguments.checkInDate ?? dateTimeNow,
initialLastDate: arguments.checkOutDate ?? dateTimeNow.add(Duration(days: 1)),
firstDate: dateTimeNow,
lastDate: dateTimeNow.add(Duration(days: 365 * 10)));
if (picked != null && picked.length == 2) {
context.read<HotelChangeParamsBloc>().setCheckInDate(picked[0]);
context.read<HotelChangeParamsBloc>().setCheckOutDate(picked[1]);
}
}
Now, the issue here is that from a Dialog I open a popup with the DateRangePicker, pick the Date and submit it but on the Dialog the date stays the same as it was previously. And if I close and re-open the Dialog I can see that there was a change in the date. So the Dialog is not refreshing the data by itself(unless I re-open it).
Does anyone know how I can refresh the Dialog with the new Date from the DateRangePicker?
Edit:
If you're interested in adhering to the intended Bloc pattern, you wouldn't be firing a regular function from your dialog. That's why I said 'assuming you're emitting a new state'.
Ideally it would be
context.read<HotelChangeParamsBloc>().add(UserSelectedDateEvent(setCheckInDate(picked[0])));
In that example UserSelectedDateEvent is an event that passes in a DateTime object that gets emitted to an updated state.
That event would hit the mapEventToState method in your Bloc, emit a new state, and if you wrap your first dialog in a BlocBuilder as mentioned below, it will show the updated date
Original answer:
Assuming that your setCheckInDate() method is emitting a new state in your HotelChangeParamsBloc, you just need to wrap your first dialog in
BlocBuilder<HotelChangeParamsBloc, HotelChangeParamsBlocState>
Then within that, display the updated date with state.yourBlocVariable.toString()
Without the BlocBuilder theres nothing telling it to rebuild so it won't show the updated state until you close and rebuild it.

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 - TextFormField, onChanged doesn't appear to be updating value

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.