Flutter go_router how to return result to previous page?
Asked Answered
T

10

36

I'm trying to open a page and get returned result with go_router package. In Navigation 1.0 I use this:

final result = await Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => const SecondRoute()),
);
// handle result

But I can't seem to do it with go_router. Any solution or explaination?

Tumble answered 5/3, 2022 at 4:14 Comment(0)
S
26

The latest version of go_router package now supports this functionality. To pass data when popping from a screen, you can do this:

context.pop('value');

And to get this value back, your code should look like this:

String? val = await context.pushNamed('secondRoute');

Hope this helps, thank you

Squarerigger answered 19/4, 2023 at 9:56 Comment(1)
Note: This feature is from version 6.5.0 and aboveCrawford
E
7

You can do this with GoRouter.of(context).addListener.

First you push your new page and add a listener afterwards

GoRouter.of(context).push("/page/${page!.id}/edit");
GoRouter.of(context).addListener(watchRouteChange);

The listener function can look something like this

  watchRouteChange() {
    if (!GoRouter.of(context).location.contains("/edit")) {  // Here you check for some changes in your route that indicate you are no longer on the page you have pushed before
      // do something
      GoRouter.of(context).removeListener(watchRouteChange); // remove listener
    }
  }


Eve answered 5/10, 2022 at 15:33 Comment(4)
How to get returned result in this case?Eran
The question demands to persist the result . Which is missing in your codeLoiseloiter
what are you saying??Horseleech
as of v9.0.0 this is no longer the case :/ github.com/flutter/flutter/issues/129800Hibernate
L
3

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');
  }
});
Loiseloiter answered 4/1, 2023 at 3:21 Comment(0)
P
2

You can use the callback by putting the function in extra object when push new screen.

Example Screen A -push-> Screen B ->pop with result -> Screen A (get results)

  1. Define the function type to put


typedef AddNewEventResult = void Function(Result result);


  1. Push A -> B


GoRoute(
path: kScreenB,
builder: (BuildContext context, GoRouterState state) => ScreenB(addNewEventResultstate.extra! as AddNewEventResult),
)


  1. When screen B has done, just pop from B to A and attached the result (Result)


Navigator.of(context).pop();
widget.addNewEventResult(true, Result());


Pinette answered 5/12, 2022 at 6:55 Comment(0)
E
2

Unfortunately, the functionality you are looking for is not provided by GoRouter at this time.

An alternative to using go_router_flow is to implement something simple yourself by passing callbacks as the extra property on GoRouterState.

This dartpad contains a full example, but the gist is that you define your routes similar to:

GoRouter(
  initialLocation: "/",
  routes: <RouteBase>[
    GoRoute(
      path: "/second",
      builder: (_, state) {
        final params = state.extra! as SecondPageParams;

        return SecondPage(params: params);
      },
    ),
  ],
);

And define your SecondPage similar to:

class SecondPageParams {
  final void Function(String data) action;
  
  const SecondPageParams(this.action);
}

class SecondPage extends StatelessWidget {
  final SecondPageParams params;

  const SecondPage({super.key, required this.params});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Center(
          child: ElevatedButton(
            onPressed: () {
              context.pop();
              params.action("Data from second page");
            },
            child: const Text("Pop and perform action")
          ),
        ),
      ),
    );
  }
}

It's not as clean as being able to await a context.push, but this is a simple way you can specify the action that you want to take whenever SecondPage is popped off the stack without having to rely on a different package.

Erma answered 27/2, 2023 at 3:20 Comment(0)
D
1

in the documentation : https://pub.dev/documentation/go_router/latest/topics/Navigation-topic.html

Waiting for a value to be returned:

onTap: () {
  final bool? result = await context.push<bool>('/page2');
  if(result ?? false)...
}

Returning a value:

onTap: () => context.pop(true)
Deitz answered 6/5, 2023 at 12:39 Comment(0)
T
0

As of answer time, only support for doing

 List<Archive> selectArchives = await Navigator.of(context).push(
            MaterialPageRoute(
                builder: (context) => const ArchiveListPage(
                    selectMode: true, canSelectCount: 1)));

 context.pop(_selectArchives);
Tav answered 1/3, 2023 at 7:42 Comment(0)
S
-1

This flow is described in the docs here: https://gorouter.dev/user-input

Generally you have to update the data and return some value back as a route with params and the screen itself should manage updates / data manipulation.

I don't want to copy paste their code here, but the answer you are looking for is in the docs page above.

Updated with link from archive: https://web.archive.org/web/20220325235726/https://gorouter.dev/user-input

Thanks ahmetakil

Saunders answered 10/3, 2022 at 9:33 Comment(11)
I didn't get it that using user input. Can you please add code here to get data back from screen 2 to screen 1 (previous screen) ?Skepful
@Skepful please follow docs, they are well documented & self-explainable.Saunders
As I understand, the documentation basically says that there is no way to await a result using the go_router. It suggests you do the data handling in the "user input page" and navigate away when you saved the data without returning to the original page. This means you can't do a simple picker screen (in my case pick a place from a full-screen map). The only way you can do this is to use the plain navigator API and handle everything manually (eg.: navigation guards, route-based providers that are injected by the router, etc.).Mundy
Theres an open issue here: github.com/flutter/flutter/issues/99663. It might solve your problem once its done.Tenfold
@OlegNovosad context.pop() stated on that page doesn't really go back the browser history, instead it is going to a new page. The documentation isn't really well documented for me.Retractile
I found that if you want to go back successfully by context.pop(), you would need to use context.push('path') instead of context.go('path'). However, on that documentation page it paired context.pop with context.go, which is confusing to meRetractile
Would like to mention to the commenters that I'm not the representative of the go_router :) I found that if you follow documentation properly - it can solve the issues with navigation.Saunders
You should've added the code here because the link is not working anymore.Georginegeorglana
@Georginegeorglana thanks for your comment. From what I've found is that Flutter team is adopting go_router package and though they disabled the original website and the new one is located here: pub.dev/documentation/go_router/latest/topics/… but it does not have that information so far. Will search for a code sample.Saunders
link is not working anymoreEran
Here is a web archive link since the website is not working at the moment web.archive.org/web/20220325235726/https://gorouter.dev/…Sacaton
L
-3

if you use Gorouter you can use

GoRouter.of(context).pop();

Load answered 24/2, 2023 at 15:57 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Baer
B
-6

When you are done with the next screen just use Navigator.pop(context,true); and true is something that you want to send to the previous screen. You can send anything I'm just using true for reference. This will allow your result variable to get data and perform anything.

Bittencourt answered 5/3, 2022 at 4:50 Comment(2)
You need to access the returned data from the 2nd page on the 1st page? Is that what you were trying to say ?Bittencourt
I'm asking about go_router package. Not how Navigator.push Navigator.pop work, I know this. go_router do not return Future like Navigation 1.0Tumble

© 2022 - 2024 — McMap. All rights reserved.