Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -439,5 +439,86 @@ moduleFor(
assert.equal(this.routerService.get('currentURL'), '/?url_sort=a');
});
}

async ['@test Redirecting to same route with query params from beforeModel works via transition'](
assert
) {
assert.expect(2);

this.add(
'route:parent.child',
class extends Route {
@service
router;

beforeModel(transition) {
if (!transition.to.queryParams.bar) {
return this.router.transitionTo('parent.child', {
queryParams: { bar: '1' },
});
}
}
}
);

this.add(
'controller:parent.child',
Controller.extend({
queryParams: ['bar'],
bar: null,
})
);

await this.visit('/');
await this.routerService.transitionTo('parent.child').followRedirects();

assert.equal(
this.routerService.get('currentURL'),
'/child?bar=1',
'redirected to self with query param'
);

assert.equal(this.routerService.get('currentRouteName'), 'parent.child');
}

async ['@test Redirecting to same route with query params from beforeModel works via direct visit'](
assert
) {
assert.expect(2);

this.add(
'route:parent.child',
class extends Route {
@service
router;

beforeModel(transition) {
if (!transition.to.queryParams.bar) {
return this.router.transitionTo('parent.child', {
queryParams: { bar: '1' },
});
}
}
}
);

this.add(
'controller:parent.child',
Controller.extend({
queryParams: ['bar'],
bar: null,
})
);

await this.visit('/child');

assert.equal(
this.routerService.get('currentURL'),
'/child?bar=1',
'redirected to self with query param'
);

assert.equal(this.routerService.get('currentRouteName'), 'parent.child');
}
}
);
32 changes: 20 additions & 12 deletions packages/router_js/lib/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,19 +208,27 @@ export default abstract class Router<R extends Route> {
if (routeInfosEqual(newState.routeInfos, oldState!.routeInfos)) {
// This is a no-op transition. See if query params changed.
if (queryParamChangelist) {
let newTransition = this.queryParamsTransition(
queryParamChangelist,
wasTransitioning,
oldState!,
newState
);
newTransition.queryParamsOnly = true;
// SAFETY: The returned OpaqueTransition should actually be this.
return newTransition as InternalTransition<R>;
if (!wasTransitioning) {
// Not in an active transition — use the QP-only fast path
// which updates the URL without re-resolving route hooks.
let newTransition = this.queryParamsTransition(
queryParamChangelist,
wasTransitioning,
oldState!,
newState
);
newTransition.queryParamsOnly = true;
// SAFETY: The returned OpaqueTransition should actually be this.
return newTransition as InternalTransition<R>;
}
// When a query-param-only transition is started during an active
// transition (for example, from beforeModel/afterModel), avoid the
// QP-only fast path and intentionally fall through to the normal
// transition path so it can abort and replace the active transition.
} else {
// No-op. No need to create a new transition.
return this.activeTransition || new InternalTransition(this, undefined, undefined);
}

// No-op. No need to create a new transition.
return this.activeTransition || new InternalTransition(this, undefined, undefined);
}

if (isIntermediate) {
Expand Down
Loading