Chirag Mevada
Chirag Mevada

Reputation: 317

How can i do push replacement using go router package in flutter [go router]

I am using the go router plugin for my flutter web application, but I didn't find any way to do push replacement in navigation.

not only push replacement, can we do any other type of navigation link

What I tried

they only pushed the next page, not replacing

Note: I want this functionality in go router

Upvotes: 13

Views: 27080

Answers (13)

Rustam Usmanov
Rustam Usmanov

Reputation: 312

You can separately use route functions, for example if you want to use pushNamedAndRemoveUntil, you can try it adding by onExit function inside of your router. I tried this:

final GoRouter _router = GoRouter(
 routes: [
   GoRoute(
     path: '/',
     builder: (context, state) => Container(),
   ),
   GoRoute(
     path: '/admin',
     builder: (context, state) => const Login(),
   ),
   GoRoute(
     path: '/admin/home',
     onExit: (_) => false,  <--- Added this line. This just terminate the operation
     builder: (context, state) => const Home(),
   ),
 ],
);

and so on. There are another functions available to use. The same with redirect. There is redirect argument function in GoRouter class. you can try it one by one

Upvotes: 0

Giraldi
Giraldi

Reputation: 17291

Here's a workaround that I did. I created an extension to BuildContext.

extension GoRouterContextX on BuildContext {
  void _doPop<T extends Object?>([T? result]) {
    if (Navigator.of(this).canPop()) {
      pop(result);
    }
  }

  /// Pop repeatedly until the specified location.
  ///
  /// If non-null, `result` will be used as the returned result.
  void popUntil<T extends Object?>(String location, [T? result]) {
    final routeInfo = GoRouter.of(this).routeInformationProvider;

    final routeMatches =
        (routeInfo.value.state as Map?)?['imperativeMatches'] as List<Map>;

    final routeLocations = routeMatches
        .map<String>((e) => e['location'])
        .toList()
        .reversed
        .toList();

    if (routeLocations.isEmpty) {
      _doPop<T>(result);
    }

    for (var routeLoc in routeLocations) {
      if (routeLoc != location) {
        _doPop<T>(result);
      } else {
        break;
      }
    }
  }
}

Use it like this: context.popUntil(route_path_here, true);

Note:

At the time of this answer, I am using:

  • GoRouter 12.0.1
  • Flutter 3.13.9
  • Dart 3.1.5

Upvotes: 0

rubyDev
rubyDev

Reputation: 31

This is what I found from doc:

context.replace(location)

Replaces the top-most page of the page stack with the given one but treats it as the same page. The page key will be reused. This will preserve the state and not run any page animation.

Upvotes: 2

Mehmet Filiz
Mehmet Filiz

Reputation: 720

If you are using a nested or ShellRoute and want to avoid browser history to record the unnecessery navigation actions consider using neglect

onTap(){
    Router.neglect(context, () => context.go('/profile/security'));
}

Upvotes: 0

Burak Can Kurtarır
Burak Can Kurtarır

Reputation: 101

You can use something like this;

while (context.canPop()) {
  context.pop();
}
context.pushReplacement(path, extra: data);

Upvotes: 4

krishnaacharyaa
krishnaacharyaa

Reputation: 24940

In the latest go_router, You can use

  1. pushReplacement - context.pushReplacement('/login');
void pushReplacement(
  String location,
  {Object? extra}
)
  1. pushReplacementNamed - context.pushReplacementName(Routes.login) (Routes is a class having defination of login)
void pushReplacementNamed(
  String name,
  {Map<String, String> params = const <String, String>{},
  Map<String, dynamic> queryParams = const <String, dynamic>{},
  Object? extra}
)

Upvotes: 10

orser
orser

Reputation: 164

I am using go_router 6 and it works with:

context.pushReplacement()

Upvotes: 3

Mohit chouhan
Mohit chouhan

Reputation: 65

Edited

i use this functions and they are useful for me

void popUntil(String name){
  GoRouter router= AppRoutes.router;
  String currentRoute=router.location;
  while(router.canPop()&&name!=currentRoute){
    currentRoute=router.location;
    if(name!=currentRoute){
      router.pop();
    }
  }
}
void pushNamedAndRemoveUntil(String name){
  GoRouter router= AppRoutes.router;
  while(router.canPop()){
    router.pop();
  }
  router.replaceNamed(name);
}

work same as pushNamedAndRemoveUntil(route_name, (Route<dynamic> route) => false);

any suggestion please drop a comment

Upvotes: 0

Valentin Vignal
Valentin Vignal

Reputation: 8192

In the current version of go_router (5.1.10), you can use GoRouter.of(context).replace('/your-route) to do the same as Navigator.of(context).pushReplacement(yourPage).

There is a PR open to add popUntil but it looks like the flutter team doesn't want to support imperative routing methods and only focus on declarative routing (see, this issue).

It means the popUntil PR might never be merged, and pushNamedAndRemoveUntil never be supported. It also means that push and replace might be removed in the future.

Upvotes: 1

Fasica Zewdie
Fasica Zewdie

Reputation: 19

I have had the same problem before. Then this way worked for me First you need to avoid nested routes:

    final GoRouter router = GoRouter(
  routes: <GoRoute>[
    GoRoute(
      path: '/',
      builder: (BuildContext context, GoRouterState state) =>
          const OnboardingScreen(),
    ),
    GoRoute(
      path: '/login',
      builder: (BuildContext context, GoRouterState state) => LoginScreen(),
    ),
    GoRoute(
      path: '/signup',
      builder: (BuildContext context, GoRouterState state) =>
          const SignupScreen(),
    ),
    
  ],
);

Use the above code instead of nesting like this:

 final GoRouter router = GoRouter(
  routes: <GoRoute>[
    GoRoute(
      routes: <GoRoute>[
        GoRoute(
          path: 'login',
          builder: (BuildContext context, GoRouterState state) => LoginScreen(),
        ),
        GoRoute(
          path: '/signup',
          builder: (BuildContext context, GoRouterState state) =>
              const SignupScreen(),
        ),
      ],
      path: '/',
      builder: (BuildContext context, GoRouterState state) =>
          const OnboardingScreen(),
    ),
  ],
);

This will make you able to replace OnboardingScreen() from the above eg. So next you can use pushreplacement future with:

context.go("/routname");

or GoRouter.of(context).go("/routname"); If u don't want replacement, then can just use:

context.push("/routname");

or

 GoRouter.of(context).push("/routname");

Upvotes: 1

Divyam Makar
Divyam Makar

Reputation: 106

What you can do is use Sub-Route Redirects in Go Router.

Let's consider you want users to first go on your Homepage and then from there they tap Login, and go to Login page and then after Logging in, they go to Dashboard Page.

But when they press Browser's Back Button they should go to Homepage and not the LoginPage i.e skipping the LoginPage just like "pushNameReplacement".

Then for this to happen you can configure redirects of each LoginPage and Dashboard page and get this functionality.

You can configure it such that whenever user (including from Browser's History) goes to Dashboard link it first checks if its Logged In then it opens otherwise it displays Login Page automatically.

Upvotes: 0

Rahul Mishra
Rahul Mishra

Reputation: 478

You can do it in a way ->

context.pop();
context.push(routeName);

Adding both these commands works similar to pushReplacement.

Upvotes: 3

Prototype
Prototype

Reputation: 568

Try this

Router.neglect(context, () {
            context
                .goNamed('third', params: {"id": ID});
          });

It will neglect your current page. Hop this will helps you

Upvotes: 6

Related Questions