Flutter: go_router how to pass multiple parameters to other screen?
Asked Answered
P

5

62

In a vanilla flutter I use to pass multiple parameters to other screen like this:

    Navigator.of(context).push(MaterialPageRoute(
                                    builder: (_) => CatalogFilterPage(
                                          list: list,
                                          bloc: bloc,
                                        )))

Pretty simple and easy. I can pass 2 needed parameters, list and bloc. After use it in CatalogFilterPage.

Now after switching to go_router and looking through documentation I can't seem to find how to pass multiple data. Even passing single object seems not that good:

    onTap: () =>
              context.pushNamed('SelectedCatalogItem', extra: list[index]),

And in router I have to use casting to set correct type:

    builder: (context, state) => SelectedCatalogItem(
                    item: state.extra as ListItemsModel,
                  ),

It was fine for single parameter. But now I don't have an idea how to pass multiple parameters. How can I do it? Is even passing parameters, like models, as an extra is right way?

P.S. I know that you can pass parameters as context.pushNamed('CatalogFilterPage', params: ___), but params has type of Map<String, String> witch not let me pass model's

Plentiful answered 14/7, 2022 at 6:20 Comment(1)
you can refer to this doc - docs.flutter.dev/cookbook/navigation/navigate-with-arguments – Saprophyte
R
188

Edit: Breaking changes in Go_router 10.0.0

enter image description here

Edit: Breaking changes in Go_router 7.0.0

enter image description here

In NutShell

Below Go Router 7  i.e < 7.0.0 use `params`, `queryParams`
Go Router 7 to 10  i.e 7.0.0 <=, < 10.0.0 use `pathParameters`, `queryParameters`
Above Go Router 10 i.e 10.0.0 <= use `pathParameters`, `uri.queryParameters`

Summary:

There are three ways: pathParameters, queryParameters, extra

  1. Using pathParameters
    • When you know the number of parameters beforehand
    • Usage : path = '/routeName/:id1/:id2'
  2. Using uri.queryParameters
    • When you are not sure about the number of parameters
    • Usage : path = '/routeName'
  3. Using extra
    • When you want to pass object

Explanation:

1. Using pathParameters

When you know number of params beforehand use pathParameters prop in context.goNamed()

Define it as:
GoRoute(
  path: '/sample/:id1/:id2',  // πŸ‘ˆ Defination of params in the path is important
  name: 'sample',
  builder: (context, state) => SampleWidget(
    id1: state.pathParameters['id1'],
    id2: state.pathParameters['id2'],
  ),
),
Call it as:
ElevatedButton(
  onPressed: () {
    var param1 = "param1";
    var param2 = "param2";
    context.goNamed("sample", pathParameters: {'id1': param1, 'id2': param2});
  },
  child: const Text("Hello"),
),
Receive it as:
class SampleWidget extends StatelessWidget {
  String? id1;
  String? id2;
  SampleWidget({super.key, this.id1, this.id2});

  @override
  Widget build(BuildContext context) {
     ...
  }
}

2. Using uri.queryParameters

Use the queryParameters in context.goNamed() ex: context.goNamed('sample', queryParameters: {'id1': 'param1'}) function or
simply add params after the ? in the URL of context.go() ex: context.go('/sample?id1=param1').
The best thing about queryParameters is that you don't have to explicitly define them in your route path and can easily access them using the state.uri.queryParameters method. You can add miscellaneous user-related data as a query parameter.

Define it as :
GoRoute(
  name: "sample",
  path: "/sample",          
  builder: (context, state) => SampleWidget(
      id1: state.uri.queryParameters['id1'],
      id2: state.uri.queryParameters['id2'],
  ),
)
Call it as:
ElevatedButton(
  onPressed: () {
    var param1 = "param1";
    var param2 = "param2";
    context.goNamed("sample", queryParameters: {'id1': param1, 'id2': param2});
    // context.go("/sample?id1=$param1&id2=$param2"); πŸ‘ˆ or like this.
  },
  child: const Text("Hello"),
),
Receive it as:
class SampleWidget extends StatelessWidget {
  String? id1;
  String? id2;
  SampleWidget({super.key, this.id1, this.id2});

  @override
  Widget build(BuildContext context) {
     ...
  }
}

3. Using extra

Use this when you want to pass a model/object between routes

GoRoute(
  path: '/sample',
  builder: (context, state) {
    Sample sample = state.extra as Sample; // πŸ‘ˆ casting is important
    return GoToScreen(object: sample);
  },
),

Refer https://mcmap.net/q/323310/-go_router-pass-object-to-new-route for passing object between routes

Rainout answered 15/12, 2022 at 15:21 Comment(6)
if anyone having issues accessing the extra object in the State then you can do this by using widget getter like this widget.object – Tagmeme
I'd add something to this answer, maybe it's a good design to parse/extract/cast the parameters in GoRouterWidgetBuilder builder: (context, state) {} but also could access the state inside the screen by calling GoRouterState.of(context) to get params, queryParams and extra – Anastomosis
Do I need to use namedRoute if I want to use queryParams? I was wondering why I can't simply pass it using standard route. – Vex
For query parameters, GoRouterState no longer has queryParameters accessible directly from state. Instead, use state.uri.queryParameters – Mathers
How to pass multiple objects please? – Registered
@Registered create a model that contains list of objects can be array or key value pairs then parse it , similar to parsing to and from model during API Request – Rainout
E
11

I am new to Flutter, but here is how I passed multiple parameters/arguments to a route with GoRouter using the extra property of context.push():

// navigate to /my-path, pass 2 arguments to context.state.extra
context.push("/my-path", extra: {"arg1": firstArg, "arg2": secondArg});

Then, inside my route:

// ...
// Use arguments in builder of the GoRoute
GoRoute(
  path: '/dashboard',
  builder: (context, state) {
    Map<String, MyCustomType> args =
      state.extra as Map<String, MyCustomType>;
    return MyWidget(arg1: args["arg1"]!, arg2: args["arg2"]!);
  }
),
// ...
Electroencephalogram answered 12/12, 2022 at 21:51 Comment(1)
what is MyCustomType ? – Stalactite
E
8

Here is a solution with my own code. In my case, i want to parse MenuModels from HomeScreen to another screen (ItemScreen):

context.push(
    '/item-screen',
    extra: widget.menuModels,
),

And in my route.dart

GoRoute(
    path: '/item-screen',
    builder: (context, state) {
        MenuModels models = state.extra as MenuModels;
        return ItemScreen(
            menuModels: models,
        );
    },
),
Elizabethelizabethan answered 3/12, 2022 at 8:14 Comment(2)
what about If we have more than one extraItem? For example, think the itemscreen has both menu models and usermodels? so, how we can push? – Milner
Use List<Object> as your extra and and pass it as extra: [object1, object2]. – Norward
E
4

From the go_router documentation we can see that:

The extra object is useful if you'd like to simply pass along a single object to the builder function w/o passing an object identifier via a URI and looking up the object from a store.

What you can do instead is pass in the id/name of the 'SelectedCatalogItem' as params and form the Object later on (if possible). The 'params' parameter lets us pass in more than one fields

onTap: () => context.pushNamed('SelectedCatalogItem',
                  params: {"id":list[index].id.toString(),"name":list[index].name}),

Then in the builder function of the GoRouter we can do:

GoRoute(
        path: 'selectedCatalogItem/view/:id/:name',
        name: 'SelectedCatalogItem',
        builder: (context, state){
          int id = int.parse(state.params['id']!);
          String name = state.params['name']!;
          // use id and name to your use...
        });
Eisegesis answered 21/8, 2022 at 9:14 Comment(1)
Hi, I am getting an error when using your code: missing param "id" for /all/:name/:id How to fix this error? – Gallice
M
0

You can use extra and pass to it map like this

GoRoute(
          path: '/path',
          name: 'path-name',
          builder: (context, state) {
            Map<String, dynamic> extra =
                state.extra as Map<String, dynamic>;
            return ScreenName(
              par1: extra['par1'],
              par2: extra['par2'],
            );
          },
        ),

and call it like this

context.goNamed(
        'path-name',
        extra: {
          'par1': object1,
          'par2': object2,
        },
      ),
Metzgar answered 27/6, 2024 at 12:31 Comment(0)

© 2022 - 2025 β€” McMap. All rights reserved.