WORKAROUND
While the answer from @CommonSense works, maybe we could tweak it a little, avoiding pop when GoRouter cannot pop.
And have this in mind. At the end, this is just a workaround and can leave to unexpected behaviors, specially with GoRouter upgrades in the future.
void popUntilPath(String routePath) {
final router = GoRouter.of(context);
while (router.location != routePath) {
if (!router.canPop()) {
return;
}
debugPrint('Popping ${router.location}');
router.pop();
}
}
THE RIGHT WAY?
Another way to do that (which seems to be the right way of doing this) is to use .go
with the correct route declaration, like this:
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Go Router Demo',
routerConfig: GoRouter(
initialLocation: '/login',
routes: [
GoRoute(
name: '/login',
path: '/login',
builder: (_, __) => const Login(),
routes: [
GoRoute(
name: 'step-1',
path: 'step-1',
builder: (_, __) => const Step1(),
),
GoRoute(
name: 'step-2',
path: 'step-2',
builder: (_, __) => const Step2(),
),
],
),
],
),
);
}
}
class Login extends StatelessWidget {
const Login({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Entry Page')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Login entry page'),
ElevatedButton(
onPressed: () => GoRouter.of(context).pushNamed('step-1'),
child: const Text('Go to step 1'),
),
],
),
),
);
}
}
class Step1 extends StatelessWidget {
const Step1({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Step 1')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Step 1'),
ElevatedButton(
onPressed: () => GoRouter.of(context).pushNamed('step-2'),
child: const Text('Go to step 2'),
),
],
),
),
);
}
}
class Step2 extends StatelessWidget {
const Step2({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Step 2')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Step 2'),
ElevatedButton(
onPressed: () => GoRouter.of(context).goNamed('/login'),
child: const Text('Go to login'),
),
],
),
),
);
}
}
When you call goNamed
to /login
, it will do a pop until login, which is what you want.
If you don't declare you routes like this (maybe you are using the imperative API) the GoRouter will go
to that route but by adding it into the stack and not just removing the other routes.
login
route, remove all routes below it and keep routes above it (if any)? – Dyadiclogin
and anything below it remains as is – Curiositycontext.goNamed('/login')
does not work in this case? If there are routes which are not included in/login
named route, they will be removed from the stack. – Dyadic