Provider file
class TermsOfServiceProvider extends ChangeNotifier {
bool _termsOfService = false;
bool get termsOfService => _termsOfService;
void termsOfServiceUpdated(bool value) {
_termsOfService = value;
notifyListeners();
}
}
Above is the provider I am using.
CheckoutButton(
onPressed:
context.watch<TermsOfServiceProvider>().termsOfService
? () {
orderAddressBloc.handleFormSubmit(
addressFormValues!.value,
customerInfoFormValues!.value,
useAsBilling: useAsBillingValue.value,
optedIn: optIn.value,
termsAndConditions: termsConditions.value,
);
}
: null,
blocLoadingIndicator: orderAddressBloc.loadingIndicator,
),
Above is where I am using the value.
But when I'm popping away from this page and returning the value of termsOfService when coming back is not changing.
I am using a checkbox for handling the data validation so when it is true it is activating a button to be clicked and false the button is inactive.
But when I am clicking for it to be true and navigating away and coming back the checkbox is not ticked but the value is true, setting the button to active when it shouldn't be.
child: CheckboxListTile(
value: checkedValue,
onChanged: (bool? newValue) {
context
.read<TermsOfServiceProvider>()
.termsOfServiceUpdated(newValue!);
setState(() {
checkedValue = newValue;
});
},
Above is the checkbox code.
You are not properly resetting the value of _termsOfService when navigating away and returning to the page. you can fix it by using the didChangeDependencies method in your CheckoutButton widget to reset the value of _termsOfService when the widget is rebuilt.
#override
void didChangeDependencies() {
super.didChangeDependencies();
final provider = Provider.of<TermsOfServiceProvid(context,listen:false);
provider._termsOfService = false;
}
This will reset the value of _termsOfService to false when the widget is rebuilt, so the checkbox will be unticked and the button will be inactive when the user navigates back to the page.
Related
I have got a State Management Problem I couldn't get rid of and I want to reach out to you.
Basically, I activate with the Buttons a game and I am sending a String to the uC. The uC does its stuff and sends a response to Flutter including gameFinished=true (that works).
Now I want to reset the State of the Button to the init state WITHOUT pressing the Button. Following are some things I tried that didn't work.
#override
void initState() {
super.initState();
setState(() {
gameAktivated = false;
gameStarted = false;
});
}
void asyncSetState() async {
setState(() async {
gameAktivated = false;
gameStarted = false;
});
}
I am changing the style from "Start" to "Stop" when the Button is pressed and I send Data to the uC. (Works)
Edit: Ofc I have a second button that triggers gameAktivated=true :)
ElevatedButton(
onPressed: () {
if (gameAktivated) {
setState(() {
gameStarted = !gameStarted;
});
if (gameStarted) {
//Send Data to uC
} else if (!gameStarted) {
//Send Data to uC
}
}
},
child:
!gameStarted ? const Text('Start') : const Text('Stop'),
),
Button Displays Stop now.
Following I am receiving a String from the uC that I jsonEncode and I receive gameFinished=true. (Works)
Container(
child: streamInit
? StreamBuilder<List<int>>(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<List<int>> snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
if (snapshot.connectionState ==ConnectionState.active) {
// getting data from Bluetooth
var currentValue =const BluetoothConnection().dataParser(snapshot.data);
config.jsonDeserializeGameFinished(currentValue);
if(config.gameFinished){
setState(() {
gameAktivated = false;
gameStarted = false;
});
asyncSetState();//Tested both methods seperate!
}
return Column(
children: [
Text(config.time.toString()),
],
);
} else {
return const Text(
'Check the stream',
textAlign: TextAlign.center,
);
}
},
): const Text("NaN",textAlign: TextAlign.center,),
),
When I try to reset the state like in the code above this error occures:
Calling setState Async didnt work for me either.
Where and how can I set the state based on the response from the uC?
Is it possible without using Provider Lib?
Thanks in advance Manuel.
Actually this error is not about the changing the state of button. Its a common mistake to update the widget state when its still building the widget tree.
Inside your StreamBuilder, you are trying to update the state before creating the UI which is raising this issue.
if(config.gameFinished){
setState(() {
gameAktivated = false;
gameStarted = false;
});
This will interrupt the build process of StreamBuilder as it will start updating the whole page. You need to move it out of the StreamBuilder's builder method.
To do that simply convert your stream to a broadcast, which will allow you to listen your stream multiple time.
var controller = StreamController<String>.broadcast();
Then inside the initState of the page you can setup a listener method to listen the changes like this
stream.listen((val) => setState((){
number = val;
}));
Here you can change the state values because from here it will not interrupt the widget tree building cycle.
For more details see this example I created
https://dartpad.dev/?id=a7986c44180ef0cb6555405ec25b482d
If you want to call setState() immediately after the build method was called you should use:
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
// this method gets called once directly after the previous setState() finishes.
});
Answer to my own Question:
In initState()
added this:
stream.listen((event) {
String valueJSON = const BluetoothConnection().dataParser(event);
config.jsonDeserializeGameFinished(valueJSON);
if (config.gameFinished) {
setState(() {
gameAktivated = false;
gameStarted = false;
});
}
});
The Code above listens to the stream, UTF-8 Decodes and JSON-Decodes the data. After this you can access the variable to set a state.
I am using Flutter with GetX plugin and I have three radio buttons inside statelesswidget but the radio button doesn't changed to selected when user click on it so my question is how I can update the selected radio using GetX plugin. here is my code
activeColor: mainColor1,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
// checkColor: Colors.white,
value: isSelected,
onChanged: (value) {
print('=====');
setState(() {
isSelected = value;
widget.onPress(value);
});
})
),
and here is my controller side
changeStatus(String select, bool condition) {
if (condition) {
selected.add(select);
} else {
selected.remove(select);
}
print(selected.length);
update();
}
you have to initialize your controller like this:
final Controller _controller = Get.put(Controller());
call your method like this in onChanged:
_controller.your method
& put the whole dropdown widget in:
Obx(()=>DropdownButton)
Using DropdownButtonFormField element to show a lists of cities. It works fine on change event and show the selected item on change event. Issue is that once I try to show selected item from set state its not working. Although state is successfully set and working.
Here is my DropdownButtonFormField code:-
DropdownButtonFormField(
value: _city,
onChanged: (String newValue) {
setState(() {
_city = newValue;
});
},
// initialValue: 'Male',
items: ['Ajman','Al Ain','Dubai','Fujairah','Ras Al Khaimah', 'Sharjah', 'Ajman','Umm Al Quwain']
.map((cityTitle) => DropdownMenuItem(
value: cityTitle, child: Text("$cityTitle")))
.toList(),
)
I set _city in InitState
#override
void initState() {
setFilters();
super.initState();
}
setFilters(){
setState(() {
_city = "Dubai";
});
}
But it's not showing selected value. How can I fix that ?
Meanz when I want to set value of _city from initState its not working
Hi I am having an issue with radio and checkbox on flutter. I have created my own widget on the purpose of having different return widget depending on what is needed as on the picture bellow since I selected change pin the return will be a checkbox but the return widget is a checkbox while the save button is stagnant or didn't change but I am having an issue when i used radio or check box even Visibility. When I try to update the setState() it is not updating or reloading the widget. The code below is just the first return of the widget which will be a check box. When i try to unchecked the button the value becomes falls but the UI is not unchecked.
sample Image
Widget getInputType(val){
if(val == 'Pin Lock'){
return CheckboxListTile(
title: Text('Pin Login'),
value: isSwitchPin,
onChanged: (value){
setState(() {
print(value);
this.isSwitchPin = value;
});
});
}
}
You can try:
1, Define a field
ValueChanged<bool> onEnventChange;
2, On initState()
onEnventChange = (value){
setState(() {
print(value);
this.isSwitchPin = value;
});
});
3, Define your function
Widget getInputType(val){
if(val == 'Pin Lock'){
return CheckboxListTile(
title: Text('Pin Login'),
value: isSwitchPin,
onChanged: onEnventChange);
}
}
I have a simple DropdownButton element and onChange event.
onChanged: (String newValue) {
if (newValue == "Log out") {
print("Inside IF");
setState(){
user.navigateToPreviousPage(Login(), context, false);
}
}
},
But from here I only get this print("Inside IF")... It does not call function which should remove user's token and navigate to login page.
In addition, there are no errors or warnings...
What is wrong here? My whole class is Stateless Widget. Should I change it to Stateful?
You are calling setState in a wrong way:
setState(){
user.navigateToPreviousPage(Login(), context, false);
}
Correct way:
setState(() {
user.navigateToPreviousPage(Login(), context, false);
});
And you should call Navigator.pop from the widget you want to dismiss :)