Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to popUntil in go router in flutter

I was wonder if there is alternative to Navigator's popUntil() method, or any workaround to achieve the same.

If i were to use Navigator. I would use like so:

void _logout() {
  Navigator.popUntil(context, ModalRoute.withName('/login'));
}

How to achieve the same in go router ?


I see a github issue - [go_router] Implement popUntil #2728, but there is no positive outcome of the same.

like image 358
krishnaacharyaa Avatar asked Feb 03 '26 00:02

krishnaacharyaa


2 Answers


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.

like image 130
Acácio Veit Schneider Avatar answered Feb 04 '26 13:02

Acácio Veit Schneider


go_router: 10.2.0

///Navigate back to specific route
void popUntilPath(BuildContext context, String routePath) {
 while (
  router.routerDelegate.currentConfiguration.matches.last.matchedLocation !=
      routePath) {
  if (!context.canPop()) {
  return;
  }
 context.pop();
 }
}
like image 44
santosh adhikari Avatar answered Feb 04 '26 15:02

santosh adhikari