Search code examples
flutterdartroutesnavigationflutter-go-router

Flutter: go_router how to pass multiple parameters to other screen?


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


Solution

  • 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://stackoverflow.com/a/74813017/13431819 for passing object between routes