Flutter - DropdownButton onChanged does not call a function - flutter

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 :)

Related

Flutter no state changes when using Navigator.of(context).push(..) in a GestureDetector

I'm building a product store right now. I have a product Card which is using a GestureDetector to navigate to the SingleProductPage. In my SingleProductPage I am using a callback function to add/remove this product as a favorite. When using one of these Callback function, my Stateful Widget will change the state to the new favorite product list. But for some reason, my SingleProductPage doesn't get the new state and the page wont rebuild. All other widgets are getting rebuilded when changing the state.
This is my GestureDestectore in the product card:
GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => SingleProductPage(product, account, favorites,
addFavoriteCallback, removeFavoriteCallback)));
},
This is what my favorite button does on remove favorite:
if(favoriteId != null) {
removeFavoriteCallback(favoriteId);
}
And this is what happens when the removeFavoriteCallback gets executed:
void onRemoveFavorite(int favoriteId) {
if (_userAccount != null) {
favoriteService
.deleteFavorite(
FavoriteDeleteRequest(_userAccount!.userId, favoriteId))
.then((value) => getFavoritesByUser());
}
}
void getFavoritesByUser() {
if (_userAccount != null) {
favoriteService.getFavoritesByUser(_userAccount!.userId).then((value) => {
if (value != null)
{
setState(() {
_favorites = Favorites(value.products);
})
}
});
}
}
As I understand you call a function that has setState() in it, which updates the widget function is called from(which is product card in your example), simple solution would be to wrap in setState() as well
if(favoriteId != null) {
setState(() =>removeFavoriteCallback(favoriteId));
}
so you update your single card widget

Why does setState works after Navigator.push?

I wonder why does setState works after Navigator.push? Actually, I met such examples, but how does it work, should not the Navigator.pushNamed redirect right when it called?
if (user != null) {
Navigator.pushNamed(context, "/chat");
}
// will the setState be executed?
setState(() {
showSpinner = false;
});

How to update future of future builder

Say I have a FutureBuilder and its future is getBusinessListByRating(), which makes a call to an API to get a BusinessList sorted by Rating. Then I press a button to sort the list alphabetically. When I do this, I want the future to be getBusinessListByAlpha() and to rerender.
How can I achieve this?
I tried using setState to update the future but it does not work.
In your state class you should initialize the future like this:
Future getBusinessListFuture;
#override
void initState() {
super.initState();
getBusinessListFuture = getBusinessListByRating(rating);
}
and in your FutureBuilder:
FutureBuilder(
future: getBusinessListFuture,
builder: ....
)
to update future on button click:
onTap: () {
setState(() {
getBusinessListFuture = getBusinessListByRating(alphabetical);
});
}
This should update the future and rebuild the widget.
How about having a method that takes an argument instead, and just alter the argument. Then let that function call your specific secondary methods.
Something like:
enum BusinessListOrdering {
rating,
alpha,
score
}
getBusinessListBy(BusinessListOrdering order) {
switch (order) {
case BusinessListOrdering.rating:
return getBusinessListByRating();
case BusinessListOrdering.alpha:
return getBusinessListByAlpha();
case BusinessListOrdering.score:
return getBusinessListByScore();
default:
return getBusinessListByRating();
}
}
So when you press the button, you set the state for the enum variable in your widget.
onPressed: () {
setState(() {
order = BusinessListOrdering.alpha;
});
},
and the FutureBuilder instead calls:
getBusinessListBy(order)

I need to press the button 2 times in order to function (flutter)

I have a problem implementing a login button, when I press it, it will not function at first, but when I press it again (same value fields) it works.
here's my code
Button:
Center(child: RaisedButton(onPressed: (){
setState(() {
onPressedLogin(userName.text,password.text);
});
}
The OnPressedLogin():
void onPressedLogin(String userName,String password) async{
bool isValid = false;
var value = await dataBaseHelper.getUserList();
for(User userOB in value){
//print(userOB.password+" "+password),
if(userName == userOB.username && password == userOB.password) {
isValid = true;
this.password.clear();
this.userName.clear();
inputTextColor = Colors.grey[850];
invalidCredentials = "";
print("YES");
//Navigator.push(context, MaterialPageRoute(builder: (context) => Home()));
break;
}
}
if(!isValid){
inputTextColor = Colors.red[800];
invalidCredentials = "Invalid Credentials";
}
You are using a Future but in setState() you are not waiting for it so that's way it work in the second press (the value take time to change).
To make it work with single press you have to a wait the Future to complete before rebuilding, here how:
First change the return type of the function
Future<void> onPressedLogin(String userName,String password)
Then in the RaisedButton
onPressed: () async {
await onPressedLogin(userName.text,password.text);
setState(() {});
},
The moment you setState(), the UI will refresh!
Probably that's the issue, let me explain:
What you should do is to call your function before setState(), so that the screen is refreshed with the new info.
Center(child: RaisedButton(onPressed: (){
onPressedLogin(userName.text,password.text);
setState(() {
//Variables that change for the refresh.
});
}
In your specific case, I don't see the need for SetState() as you are only printing values in log, not changing the UI.
Hope it is helpful.

is calling flutterTts.setStartHandler() method in onPressed callback of button in flutter is good practice?(flutter_tts plugin)

Scenario: I have set of children built using Listview.builder in which every child has button. Now i want when particular index of child pressed TTS(text to speech) method should be called. Implementing this is not problem. But flutter_tts plugin provides setStartHandler, setCompletionHandler methods which is called whenever tts starts and complete its work. But both that method cant be placed in initState since they need access to index variable.
body: ListView.builder
(
itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int index) {
return Column(children:[RaisedButton(onPressed:(){
flutterTts.setStartHandler(() {
setState(() {
ttsState = TtsState.playing;
litems[index].isPlaying = true;
});
});
flutterTts.setCompletionHandler(() {
setState(() {
ttsState = TtsState.stopped;
litems[index].isPlaying = false;
});
});
//custom speak() method which invokes TTS
_speak(litems[index].text);
//rest of the code
},
child:widget)
,],
);
}
)
Above code is just example.
please tell me is this good approach or is there any better solution
Thanks in advance