[go_router] Keep params in nested routes (#975)
diff --git a/packages/go_router/CHANGELOG.md b/packages/go_router/CHANGELOG.md
index f015d5f..e08a182 100644
--- a/packages/go_router/CHANGELOG.md
+++ b/packages/go_router/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 3.0.3
+
+- Fixed a bug where params disappear when pushing a nested route.
+
## 3.0.2
- Moves source to flutter/packages.
diff --git a/packages/go_router/lib/src/go_router_delegate.dart b/packages/go_router/lib/src/go_router_delegate.dart
index e4279df..38d2fee 100644
--- a/packages/go_router/lib/src/go_router_delegate.dart
+++ b/packages/go_router/lib/src/go_router_delegate.dart
@@ -338,11 +338,16 @@
// get stack of route matches
matches = _getLocRouteMatches(loc, extra: extra);
- var params = <String, String>{};
+ // merge new params to keep params from previously matched paths, e.g.
+ // /family/:fid/person/:pid provides fid and pid to person/:pid
+ var previouslyMatchedParams = <String, String>{};
for (final match in matches) {
- // merge new params to keep params from previously matched paths, e.g.
- // /family/:fid/person/:pid provides fid and pid to person/:pid
- params = {...params, ...match.decodedParams};
+ assert(
+ !previouslyMatchedParams.keys.any(match.encodedParams.containsKey),
+ 'Duplicated parameter names',
+ );
+ match.encodedParams.addAll(previouslyMatchedParams);
+ previouslyMatchedParams = match.encodedParams;
}
// check top route for redirect
@@ -356,7 +361,7 @@
name: top.route.name,
path: top.route.path,
fullpath: top.fullpath,
- params: params,
+ params: top.decodedParams,
queryParams: top.queryParams,
extra: extra,
),
diff --git a/packages/go_router/pubspec.yaml b/packages/go_router/pubspec.yaml
index 467e3be..1d65523 100644
--- a/packages/go_router/pubspec.yaml
+++ b/packages/go_router/pubspec.yaml
@@ -1,7 +1,7 @@
name: go_router
description: A declarative router for Flutter based on Navigation 2 supporting
deep linking, data-driven routes and more
-version: 3.0.2
+version: 3.0.3
repository: https://github.com/flutter/packages/tree/main/packages/go_router
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+go_router%22
diff --git a/packages/go_router/test/go_router_test.dart b/packages/go_router/test/go_router_test.dart
index 1c702f3..abb247f 100644
--- a/packages/go_router/test/go_router_test.dart
+++ b/packages/go_router/test/go_router_test.dart
@@ -1353,6 +1353,44 @@
expect(page2.fid, 'f2');
expect(page2.pid, 'p1');
});
+
+ test('keep param in nested route', () {
+ final routes = [
+ GoRoute(
+ path: '/',
+ builder: (builder, state) => const HomeScreen(),
+ ),
+ GoRoute(
+ path: '/family/:fid',
+ builder: (builder, state) => FamilyScreen(state.params['fid']!),
+ routes: [
+ GoRoute(
+ path: 'person/:pid',
+ builder: (context, state) {
+ final fid = state.params['fid']!;
+ final pid = state.params['pid']!;
+
+ return PersonScreen(fid, pid);
+ },
+ ),
+ ],
+ ),
+ ];
+
+ final router = _router(routes);
+ const fid = "f1";
+ const pid = "p2";
+ final loc = "/family/$fid/person/$pid";
+
+ router.push(loc);
+ final matches = router.routerDelegate.matches;
+
+ expect(router.location, loc);
+ expect(matches, hasLength(2));
+ expect(router.screenFor(matches.last).runtimeType, PersonScreen);
+ expect(matches.last.decodedParams['fid'], fid);
+ expect(matches.last.decodedParams['pid'], pid);
+ });
});
group('refresh listenable', () {