I was using Navigator 1 then I migrated to go_router to support deep links and web.
Sometimes when I send HTTP requests, I show a loading dialog using showDialog() until the response is processed, after processing I need to check if a dialog is shown or not, if shown I dismiss it using Navigator.of(context).pop().
When I was using Navigator 1, I used to do that in this way:
if (ModalRoute.of(context)?.isCurrent == false) Navigator.of(context).pop();
But now after migrating to go_router this doesn't work as I found that ModalRoute.of(context) always equals to null whether there is a dialog shown or not.
I tried using if (Navigator.of(context).canPop()) Navigator.of(context).pop();, but this doesn't differentiate between dialogs and screens, if there is no dialog shown it pops the current screen.
You can do this by checking the location of GoRouter
if (GoRouter.of(context).location == '/dialog'){ 👈 Check here
context.pop();
}
Assuming your dialog route has path /dialog
Related
I am using firebase_ui_auth package for authentication in my first Flutter app using the code below. I am only using phone authentication provider. The problem I am facing is after I enter the OTP and click verify AuthStateChangeAction callback is triggered, inside this callback I want to navigate to the profile screen so I use the below line of code as mentioned in the documentation.
Navigator.pushReplacementNamed(context, '/profile');
But the above line doesn't takes me to the profile screen, instead after I enter the OTP and click verify it takes me again to the sign-in screen. So, I took a Codementor session and he changed the line in the AuthStateChangeAction callback to the below line.
WidgetsBinding.instance.addPersistentFrameCallback((timeStamp) {
Navigator.pushReplacementNamed(context, '/profile');
});
This takes me to the profile screen(expected behaviour) after I enter the OTP and click Verify button. But now in the logs, I am getting the below error.
Another exception was thrown: Looking up a deactivated widget's ancestor is unsafe.
So, I wanted to know answers to below questions?
what does using WidgetsBinding.instance.addPersistentFrameCallback do?
How does it affect the screen stack of my app?
Why deactivated widget's ancestor exception is raised?
Why am I not navigated to the profile screen when I don't use WidgetsBinding?
Is it fine to use WidgetsBinding for navigating to other screens?
What is the best practice for navigation to the profile screen?
let's say I navigate from page a with context.push() and pass extra to page b.
then if I navigate to page c and then press the browser back button to go back to page b now extra is null and page shows error.
any solutions?
I think we can use query parameters but it brings up security problems.
You can follow one of the two possible solution:
Dont let page to come back to B from C, You can use something like popUntil
When coming back to B from C override the naviagetion such that you send the extra object along with it. So that B has extra value
Edit:
Presently there is no way to achieve this using go_router. You can use go_router_flow which is exactly like go_router with this pop with value feature.
final bool? result = await context.push<bool>('/page2');
WidgetsBinding.instance.addPostFrameCallback((_) {
if(result){
print('Page returned $result');
}
});
Use the beamer package for routing.This problem occur in the go router.
beamer package link
I am using the AutoRoute package for Flutter.
I have the following two screens generated using the auto route package,
HomeRoute()
ProductsRoute()
Then from HomeRouteI do the following,
context.router.push(const ProductsRoute());
Then inside the ProductRoute I call an API in the initState and if I an error occurs, I show a pop up that says Something went wrong!. Here,
I want to pop the alert, then pop the ProductsRoute() so that the user navigates back to the HomeRoute().
So using the AutoRoute I did the following,
context.router.popUntil((route) => route.settings.name == 'HomeRoute')
This did not work. It leads me to a white screen.
However it does work if I do context.route.pop() twice.
Can someone please tell me what I am doing wrong and how can I navigate back to the HomeRoute() using the Auto Route package?
Thanks.
context.router.popUntil((route) => route.name == 'HomeRoute')
or
context.router.popUntilRouteWithName('HomeRoute')
I found the problem,
With popUntil, if I want to go to the HomeRoute, I should not mention the HomeRoute. Instead I should mention the route on the stack that is after the HomeRoute. Then it started to work,
For example suppose I have the following stack,
ScreenA -> ScreenB -> ScreenC -> ScreenD
Now if I want the user to show screen A by popping all the screens from screen D,
I should do,
context.router.popUntilRouteWithName(ScreenBRoute.name); // <---- Should do
NOT
context.router.popUntilRouteWithName(ScreenARoute.name); // <---- Should not do
First: forgive me if it's a dumb question, but I'm trying to figure out step by step how Navigator 2.0 works and how to implement it in my app; this seems to be the only piece left of this puzzle but I weren't able to find an answer anywhere.
I've followed this Medium article on how to implement the new Navigator inside my Flutter app but I don't get how to use it after I've finished.
I mean: I have replaced MaterialApp with MaterialApp.router, specifying the custom RouterDelegate and the custom RouteInformationParser I've created, but how can I switch from the '/home' route to the '/profile' one after I pressed a button?
With the old navigator I would have added a Navigator.of(context).pushNamed('/profile) in the onPressed function of the button in the home screen, is it still valid or now should I proceed different?
For navigator 1.0:
Navigator.of(context).pushNamed('/profile');
For navigator 2.0 (using go_router package):
GoRouter.of(context).pushNamed('/profile');
I have a typical CRUD operation task: (List Sites, Add Site, ...)
I created a SitesProvider. In the same provider, I added 2 methods for add and edit. I was thinking to use the same provider in the 2 screens (ListSites and AddEditSite)
In the ListSites screen, it works fine. Here is the problem:
I open the AddSite screen by clicking the AddButton in the ListSites screen
Hit submit (did not enter data, simulating error case)
The error gets displayed in the ListSites screen, not in the AddSite screen.
It makes sense. They both use the same provider, both screens are on the stack. It seems that the first one only consumes the state update and displays the error.
I use MultipleProviders approach that wraps the MaterialApp with all providers in the app.
Can we fix that without creating separate providers for each of the 2 screens?
EDIT:
I used provider.removeListener in the ListSites screen right before I open the AddEdit and it shows the error in the correct screen now. I still have to do some other tweaks to get it back to listen after I add. Not efficient I think but it is a step.
I ended up doing that:
Added Another Field in the provider (stateType: list/addedit)
Change the type per the screen I'm currently in
provider.stateType = UIStateType.add_edit;
await Navigator.push(context,
MaterialPageRoute(builder: (context) => AddEditSiteScreen()));
provider.stateType = UIStateType.list;
in build(), I check for the type
sitesProvider = Provider.of(context);
if (sitesProvider.stateType != UIStateType.add_edit) return Container();