I want to have page A reload, re-run the Http requests, once I pop back to it from another page that lets you edit the data page A displays. The other page is triggered by a long press in a ListView generated by a function within page A. IE:
Page A:
_PageAState
Reload function I need to call
Scaffold
List item
Text
ETC...
Expanded
ListView
Gesture Detector that navigates
ETC
How can I trigger a function of any sort or make the page reload when I pop back to it?
I've tried passing data from the pop and using an if statement but the nested structure messes it up.
of course, there's a way to do that!
As you realized, the first route needs to get notified when the pushed Route gets popped.
Thankfully, there's a tutorial in the Flutter documentation that handles returning data from Routes.
In your case, no data gets returned but you can still use the same principle to wait for the route to be popped: Simply await the Navigator.push call!
This will return once the other route gets popped.
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => OtherPage()),
);
// TODO: Now, refetch the data.
Related
I have a project that I had initially setup with Navigator and have since converted over to use BLoC Cubit.
When I use Navigator.of(context).pop(); to go back from a screen that was navigated to using context.read<AppCubits>().pageOneScreen(); I get a black screen instead of being directed back.
Does BloC Cubit's not allow or keep any history like Navigator does?
**** MORE DETAILS ****
I have a back button that would simply call
Navigator.of(context).pop()
and bring the user back to their previous page.
Now with Cubit, using the above doesn't work and returns a blank screen as there is no context stored.
So I have been searching for a solution to this but every one of them seems very verbose, is this type of feature not a part of Cubit or BLoC?
To navigate from page to page currently I am using
context.read<AppCubits>().pageOneScreen();
context.read<AppCubits>().pageTwoScreen();
This works as expected but I am looking for a solution to adding a call that will navigate back to the previous screen/state that was loaded. So if I was on pageTwoScreen, I could click back if I had come from pageOneScreen and have the state changed or at least be directed back to pageOneScreen.
Do I have to create a list and store the state value as a form of rudimentary history and then pop off the previous value and call something akin to
context.read<AppCubits>().historylistvalue()
I have stateful widget that is basically list of tasks. In that widget i also have a button that causes Dialog box to appear.
Dialog box is AlertDialog that consists of text field that has controller inside of it and Save button. Button calls state's method that does few things:
dialog box to pop so to get back to list of tasks
causes setState of stateful widget with value from controller
controller to clear
Method looks like this:
void saveNewTask() {
Navigator.of(context).pop();
setState(() {
toDoList.add([_controller.text, false]);
});
_controller.clear();
}
This method is passed all the way down to Save button, and Dialog box is of course seperate widget so Navigator gets the right context.
Considering the order in saveNewTask i would assume the order would go like this:
Dialog box gets poped off
setState gets called, stateful widget gets rebuild
controller is cleared.
but in slow motion i can see this operations don't happen in this order. Controller is cleared and widget is rebuilt before navigator pops off dialog box.
Before cliking the Save Button : -
After clicking the Save Button : -
(and after the second picture dialog box gets removed)
Digging through source code i found out that pop causes another setState of navigator's state that removes the Dialog box.
I thought that maybe popis asynchronous considering the behavior but Future is not returned so i can't use asynchronous function or thento enforce the order. setState is of course not asynchronous so i don't have a clue what's happening here??
Any clue is greatly appreciated.
The procedure you're following is not the actual way to do it.
Reasons:
AlertDialogue and the other dialogues you show are not a part of your main screen widget. It's a totally different widget. So you can't actually setState() of your widget from here.
Now you're trying to set the state of the dialogue widget which is already being removed when you say Navigator.pop();. Which is not possible. Cz that widget doesn't exist anymore.
In normal situations that controller would get destroyed too with the alert widget. But it's a good practice to manually destroy it.
So, to do it the right way these are the steps you should follow ->
First return the controller value to the main widget by passing it to the Navigator.pop(); function. In your case, just pass it for the save button value. Like this:
Navigator.pop(context, controller.text);
Now await on the showDialogue() method. And receive the value to the main widget. Something like this.
String? data = await showDialog(
context: context,
builder: (context) => AlertDialog());
Now in the main widget check if the dialogue returns a string or not. If it does, then set the state with the data you just received. And if it doesn't. In your case, when the cancel button is clicked. It will return null. Then don't do anything.
And finally, if you want to clear the controller for some reason. Then clear it before popping. And if you want to dispose it. Just dispose it inside the dispose method of your stateful widget.
When I leave a page widget and come back to it later, it retains the previous info on the previous session. I would like to create a fresh page widget from scratch every time I opened it. How do I implement this?
I am guessing that your issue is the after going to new page using Navigator.push(), you get the previous state of the page after popping the new page.
In that case you can call a setState after popping the new page. Do the following :
Navigator.pop() on Page2 :
Navigator.pop(context,1); /// Passing an extra parameter (1) to Page1 after popping
Navigator.push() in Page1 :
Navigator.push(context,MaterialPageRoute(builder: (context) => Page2())).then((value){
if(value == 1)
setState(() {}); /// Here you can keep a conditional refresh like if you pass 1 in Navigator.pop() then only will it refresh the page
/// It's useful when you want to refresh the page only for specific conditions.
});
The .then() function after Navigator.push() will be called after Page2 is popped and as mentioned in that function, a setState() will be called refreshing the page.
Are you sure that when you are navigating through the pages you close them properly (end their life circle). If not try to navigate with Are you sure that when you are navigating through the pages you close them properly (end their life circle). If not try to navigate with pushReplacement instead of push
Putting the main data of the widget in the widget declaration works. I suppose the problem was the scope of the data used. If outside the widget declaration, the data would basically be global and would be the same every time the widget is navigated to.
Is there anyway to check route name of last screen after pop? When application start and land on home screen, there are several widgets like view profile, product carousel and so on.
Scenario: User navigate into product listing page, then detail page, click purchase and perform actions. After user purchased, shows purchased successful screen, call Navigator.of(context).popUntil(routeName) back to home screen.
What I want to achieve: After land in home screen, programmatically call api to refresh my balance. Route Observer able to detect navigation back to home screen with didPopNext() method. But this is called no matter it pop from which screen. Therefore the api will repeatedly called which is not ideal. How do I know it was pop from purchased successful screen instead of product listing screen?
Grateful on any helps and hints!
If you where using pop() then you have an option to return some data to previous route but since you are using popUntil() you won't be able to do this. So I think you should clear every route and push home route again from purchased successful page using either pushAndRemoveUntil() or pushNamedAndRemoveUntil(). That means you can now pass an argument to home screen by which you can decide whether to call the API or not.
Navigator.of(context).pushNamedAndRemoveUntil(
'/',
(Route<dynamic> route) => false,
arguments: []
);
Another option would be to figure out a way to return data using popUntil(), Something like this, maybe?
this is my first app in Flutter, everything was fine and smooth util now that I´m geeting a little bit blocked.
I cannot navigate between a CupertinoTabBar and my Login display (that shouldn´t have one) the way I show you on the image.
Login works fine and when receives a 200 response from server, navigates to the view with the CupertinoTabBar.
But when I press on the LogOut button, I´d need to comeback to the loginView, without any tabBar.
The only way I´ve been able to navigate back to login is like that:
Navigator.push(context, CupertinoPageRoute(builder: (context) => LoginView()),);
And that keeps my LoginView inside the tabBar in the widgets stack, and what is worse, if I logIn again I endup stacking another tabBar over the previous one.
What could be a better approach for that?
Many Thanks,
Gabi
You can use pushAndRemoveUntil to pop routes that you don't need in stack. Probably, you want to remove all the routes like that:
Navigator.of(context).pushAndRemoveUntil(CupertinoPageRoute(builder: (context) => LoginView()), (r) => false);
or, if your current route is logout, you can replace it with login route and route stack will remain the same:
Navigator.of(context).pushReplacement(CupertinoPageRoute(builder: (context) => LoginView()));