Skip to content

Commit 73cedd7

Browse files
committed
feat(routing): pass path params to routing context
1 parent 5557706 commit 73cedd7

4 files changed

Lines changed: 62 additions & 10 deletions

File tree

lib/src/routing/domain/models/route_context.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ abstract class RouteContext extends Model with _$RouteContext {
7979
/// Retrieves a query parameter by its [key].
8080
String? getQueryParam(String key) => queryParams[key];
8181

82-
/// Retrieves a parameter by checkings [pathParams] first, then [queryParams].
82+
/// Retrieves a parameter by checking [pathParams] first, then [queryParams].
8383
String? get(String key) => pathParams[key] ?? queryParams[key];
8484

8585
/// Retrieves a parameter by checking [pathParams] first, then [queryParams].

lib/src/routing/infra/services/routing_kit_routing_service.dart

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class RoutingKitRoutingService<T, Config extends Object>
2626

2727
RouteContext? _context;
2828

29-
final Map<Uri, (Future<bool>, LeafRoute<T, Config>)> _pendingNavigations = {};
29+
final Map<Uri, (Future<bool>, LeafRoute<T, Config>, RouteContext)>
30+
_pendingNavigations = {};
3031

3132
/// The root module of the application.
3233
final RootModule<T, Config> rootModule;
@@ -250,6 +251,16 @@ class RoutingKitRoutingService<T, Config extends Object>
250251
return Uri.parse(normalized).pathSegments;
251252
}
252253

254+
RouteContext _createContext(Uri uri, Map<String, String> pathParams) {
255+
return RouteContext(
256+
fullPath: uri.toString(),
257+
pathParams: pathParams,
258+
queryParams: uri.queryParameters,
259+
queryParamsAll: uri.queryParametersAll,
260+
fragment: uri.fragment,
261+
);
262+
}
263+
253264
@override
254265
Future<void> navigate(
255266
String path, {
@@ -283,10 +294,10 @@ class RoutingKitRoutingService<T, Config extends Object>
283294
if (_pendingNavigations.containsKey(uri)) {
284295
log('Navigation to $path is already in progress, forwarding callback.');
285296

286-
final (future, leaf) = _pendingNavigations[uri]!;
297+
final (future, leaf, context) = _pendingNavigations[uri]!;
287298

288299
if (!skipPreview) {
289-
callback(leaf.view.preview(RouteContext.fromUri(uri)), true);
300+
callback(leaf.view.preview(context), true);
290301
}
291302

292303
log('Waiting for pending navigation to $path to complete.');
@@ -302,7 +313,7 @@ class RoutingKitRoutingService<T, Config extends Object>
302313

303314
log('Pending navigation to $path completed, invoking content callback.');
304315

305-
callback(await leaf.view.content(RouteContext.fromUri(uri)), false);
316+
callback(await leaf.view.content(context), false);
306317

307318
return;
308319
}
@@ -346,10 +357,11 @@ class RoutingKitRoutingService<T, Config extends Object>
346357
}
347358

348359
final (:leaf, :lineage) = _resolveLeafRoute(matchedRoute, path);
360+
final context = _createContext(uri, match.params);
349361

350-
final future = _navigate(uri, leaf, lineage, skipPreview, handler);
362+
final future = _navigate(context, leaf, lineage, skipPreview, handler);
351363

352-
_pendingNavigations[uri] = (future, leaf);
364+
_pendingNavigations[uri] = (future, leaf, context);
353365
_currentNavigation = future;
354366
await future;
355367
} catch (e, s) {
@@ -361,15 +373,15 @@ class RoutingKitRoutingService<T, Config extends Object>
361373
}
362374

363375
Future<bool> _navigate(
364-
Uri uri,
376+
RouteContext initialContext,
365377
LeafRoute<T, Config> leaf,
366378
List<Route<T, Config>> lineage,
367379
bool skipPreview,
368380
void Function(T, bool) callback,
369381
) async {
370-
var context = RouteContext.fromUri(uri);
382+
var context = initialContext;
371383
final previousContext = _context;
372-
final cleanPath = uri.path;
384+
final cleanPath = context.uri.path;
373385
final middleware = _collectMiddleware(lineage);
374386

375387
log('Navigating to $cleanPath with context: $context');

test/routing/harness/routing_test_harness.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,20 @@ class TestLeaf2 extends Leaf<String> {
271271
Future<String> content(RouteContext ctx) async => 'built:${ctx.fullPath}';
272272
}
273273

274+
class ParamLeaf extends Leaf<String> {
275+
@override
276+
String preview(RouteContext ctx) {
277+
final id = ctx.pathParams['id'];
278+
return 'preview:$id:${ctx.getPathParam('id')}:${ctx.get('id')}';
279+
}
280+
281+
@override
282+
Future<String> content(RouteContext ctx) async {
283+
final id = ctx.pathParams['id'];
284+
return 'built:$id:${ctx.getPathParam('id')}:${ctx.get('id')}';
285+
}
286+
}
287+
274288
class FeatureModule extends Module<String, Cfg> {
275289
FeatureModule(this.middlewareOrder);
276290

@@ -390,6 +404,7 @@ class RootTestModule extends RootModule<String, Cfg> {
390404
view: TestLeaf2(),
391405
middleware: [slowBlockedMiddleware],
392406
),
407+
LeafRoute<String, Cfg>(path: 'courses/:id', view: ParamLeaf()),
393408
ModuleRoute<String, Cfg>(path: 'module', module: featureModule),
394409
ModuleRoute<String, Cfg>(path: 'dependent', module: DependentModule()),
395410
const Route<String, Cfg>(path: 'idk'),

test/routing/tests/routing_test.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,31 @@ void main() {
255255
},
256256
);
257257

258+
test('passes matched path params into leaf route contexts', () async {
259+
final callbackResults = <String>[];
260+
final streamEvents = <ViewChangedEvent<String, Cfg>>[];
261+
final streamDone = Completer<void>();
262+
final sub = routing.onViewChanged((event) {
263+
streamEvents.add(event);
264+
if (streamEvents.length == 2 && !streamDone.isCompleted) {
265+
streamDone.complete();
266+
}
267+
});
268+
269+
await routing.navigate(
270+
'/courses/42?id=query#lesson',
271+
callback: (result, _) => callbackResults.add(result),
272+
);
273+
await streamDone.future;
274+
await sub.cancel();
275+
276+
expect(callbackResults, ['preview:42:42:42', 'built:42:42:42']);
277+
expect(routing.currentContext?.pathParams, {'id': '42'});
278+
expect(routing.currentContext?.queryParams, {'id': 'query'});
279+
expect(routing.currentContext?.fragment, 'lesson');
280+
expect(streamEvents.last.context?.pathParams, {'id': '42'});
281+
});
282+
258283
test('isActive returns false when no route is active', () {
259284
expect(routing.isActive('/feature/child'), isFalse);
260285
expect(routing.isActive('/feature', exact: false), isFalse);

0 commit comments

Comments
 (0)