1196 Commits

Author SHA1 Message Date
Matthieu Riegler c1c310c4a9 docs(docs-infra): remove toString from the API docs
(cherry picked from commit fc8140cff4)
2026-02-20 16:52:00 +00:00
Matthieu Riegler 6c14e3af2e build: update Jasmine to 6.0.0
Jasmine enables `forbidDuplicateNames: true` by default. So we also need to desambiguate duplicate spec names.
2026-02-09 15:57:12 -08:00
David Neil 49a36f4cc7 perf(router): Use .bind to avoid holding other closures in memory
In many JS runtimes all closures created in the same scope share a context
this means that data held in one of the closures is not collected until all of the closures are collected.
This change prevents the returned promise from holding a reaction that holds the entire `Router` object in memory.

(cherry picked from commit 3867cd8554)
2026-02-03 12:25:02 -08:00
Andrew Scott d6268c0bbb fix(router): limit UrlParser recursion depth to prevent stack overflow
Deeply nested parentheses in URLs (e.g. `(a/(b/(c...)))`) trigger recursive calls in `UrlParser`, which can lead to a `RangeError: Maximum call stack size exceeded`. While such errors are generally caught by the framework, relying on the runtime's stack limit is unpredictable across different environments and engine states (e.g. varying stack sizes in different browsers or Node.js versions).

The deeply nested parentheses  can cause a stack overflow. While such URLs can be valid (e.g., `(a/(b/(c...)))`) and serialize to simple paths (e.g., /a/b/c), excessive nesting is unreasonable and likely malicious or accidental.

Linear paths (e.g. /a/b/c/d) are parsed iteratively and do NOT trigger recursion. Only parentheses trigger recursion.

This commit introduces a recursion depth limit of 50. If parsing exceeds this depth, the router will now throw a specific `UNPARSABLE_URL` error with the message "URL is too deep". This ensures a deterministic failure mode that is easier for applications to handle than a crash or generic RangeError.

The limit of 50 is chosen as it should accommodate any reasonable application URL structure (including complex named outlets) while providing a safe upper bound against abusive payloads.

This is essentially a refactor of the error state:

* Before: RangeError (System says "I'm out of stack memory")
* After: RuntimeError (Validator says "Input is invalid")

This provides:

* Semantic Correctness: The error now correctly blames the input ("URL too deep"), not the environment ("Stack full").
* Cross-Platform Consistency: The limit is the same in Chrome, Firefox, Node, and Deno, regardless of their internal recursion limits.
* Fast Failure: We stop at depth 50 instead of depth ~15,000, saving those cycles (though CPU cost is negligible either way).

"wide" URLs are now theoretically more expensive than "deep" URLs (because deep ones fail fast), but both are well within safe bounds for any reasonable input size.

(cherry picked from commit 458bc4a2c8)
2026-01-29 12:15:25 -08:00
Andrew Scott 21ecdc036a fix(router): Do not intercept reload events with Navigation integration
This commit prevents the Router from intercepting reload navigations
in the navigate event listener. This would convert hard page reloads
to SPA navigations.

fixes #66746
2026-01-26 20:58:49 +00:00
Matthieu Riegler 18842266de docs(docs-infra): Handle additional description format
Ex: https://angular.dev/api/router/withExperimentalPlatformNavigation
(cherry picked from commit f0b1061791)
2026-01-21 19:37:11 +00:00
SkyZeroZx b1c68e66a7 docs: update examples to use isActive instead of deprecated Router.isActive (#66430)
PR Close #66430
2026-01-12 22:42:33 +00:00
Jessica Janiuk a2b9429992 Revert "feat(router): add trailingSlash config option"
This reverts commit 12fccc5e99.
2026-01-08 12:20:03 -08:00
Andrew Scott 12fccc5e99 feat(router): add trailingSlash config option
This commit introduces a highly requested `trailingSlash` configuration option to the Angular Router, allowing developers to control how trailing slashes are handled in their applications. The options are:
- 'always': Enforces a trailing slash on all URLs.
- 'never': Removes trailing slashes from all URLs (default).
- 'preserve': Respects the presence or absence of a trailing slash as defined in the UrlTree.
2026-01-08 08:26:37 -08:00
Andrew Scott 7003e8d241 feat(router): Publish Router's integration with platform Navigation API as experimental
This publishes the work that was done to integrate with the Navigation
API as an experimental router feature. Browser support is limited and in
active development. There are also known bugs in the browser implementations
and only Chromium browsers supported deferred URL updates with the
`precommitHandler`. Relates to #53321, which I would likely not mark as
completed until this is at least in dev preview, which likely won't
happen until it is widely available and potentially delayed until
`precommitHandler` is widely available as well.

The final form of this api might not even be a "router feature" in the end, but instead be
something similar to what other frameworks have to provide different
platform integrations (e.g. `provideNavigationRouter`). That would
support omitting the history-based integration from the bundle when only
the navigation integration is used. Alternatively, the current
`provideRouter` could require one of `withHistory` or `withPlatformNavigation`.
2026-01-07 16:16:06 -08:00
arturovt 9e043decaf fix(router): handle errors from view transition updateCallbackDone promise
Firefox-specific workaround: Firefox 144+ creates the `updateCallbackDone` promise
internally during error handling (e.g., duplicate view-transition-name), even before
the property is accessed. This can cause unhandled promise rejections to appear in
error tracking tools like Rollbar/Sentry. We must attach catch handlers to all three
promises immediately to prevent these unhandled rejections.
See: https://bugzilla.mozilla.org/show_bug.cgi?id=1999336 (if applicable)
Spec: https://drafts.csswg.org/css-view-transitions-1/#dom-viewtransition-updatecallbackdone
2026-01-07 15:05:59 -05:00
Andrew Scott bcef77d950 fix(router): Fix RouterLink href not updating with queryParamsHandling
There was a bug introduced in #60875. While RouterLink doesn't
necessarily depend on Router state, its link can change when navigations
cause the `ActivatedRoute` paths to change. It is difficult to determine
which segments the link depends on. Luckily, the commit had flawed
logic:

```
!this.queryParamsHandling && !dependsOnRouterState(this.options?.defaultQueryParamsHandling);
```

The subscription gets created whenever `queryParamsHandling` was not
defined, or it was non-default. This is pretty much all scenarios since
nobody is likely to set it explicitly to the default value. In addition,
the `click` handler recomputes the tree because `urlTree` is a getter
that does the computation.

This commit effectively rolls back #60875
2026-01-07 14:08:13 -05:00
Andreas Dorner 1c00ab42f8 feat(router): extend paramters of RedirectFunction to include paramMap and queryParamMap
adds paramMap and queryParamMap to the partial ActivatedRoute of the
RedirectFn

fixes ##60842
2026-01-07 12:36:54 -05:00
Andrew Scott 97fd1de0ac Revert "refactor(router): Add support for precommitHandler in Navigation integration"
This reverts commit 522fa716b8.
2026-01-07 11:45:58 -05:00
Andrew Scott 397dbc4c37 Revert "refactor(router): Retain original navigateEvent across redirects"
This reverts commit 53d3ae0feb.
2026-01-07 11:45:58 -05:00
Andrew Scott e44839b016 feat(router): Add standalone function to create a comptued for isActive
This change deprecates `Router.isActive` in favor of a function that
creates a computed which tracks whether a given url/UrlTree is active,
following changes in the router state.

`Router.isActive` contributes ~1333b to the bundle size, but is only
used by developers who use the API directly or who use
`RouterLinkActive`. It should not contribute to bundle sizes of
applications that do not use this functionality.
2026-01-07 09:23:06 -05:00
Andrew Scott 174d2da29a Revert "fix(router): Ensure createUrlTree does not reuse segments of input"
This reverts commit 39efb62c0f.
2026-01-06 16:29:19 -08:00
Andrew Scott 53d3ae0feb refactor(router): Retain original navigateEvent across redirects
This builds off of #66197 by retaining the original navigateEvent across redirects
so the NavigateEvent can more accurately track the lifecycle of a navigation,
which may span across several NavigationStart events due to redirects
2026-01-06 16:10:56 -05:00
Andrew Scott 522fa716b8 refactor(router): Add support for precommitHandler in Navigation integration
The `precommitHandler` of the Navigation API unlocks some of the truly
powerful features for Routers like Angular's which defer the URL
updates. Without the `precommitHandler`, we cannot initiate a navigation
until we are ready to commit the URL because it causes the URL to update
immediately.

With `precommitHandler` support, we are able to create a `NavigateEvent`
_immediately_ on navigation, which allows the browser to show that a
navigation is happening with a loading indicator. Site visitors will
also have the ability to cancel the navigation with the "stop" button.
When we are ready to commit the URL, the precommitHandler supports a
"redirect" function that we can use to first redirect the navigation to
a new location immediately before committing it.

The commit operation is not synchronous because the API waits for all
precommitHandlers to resolve. This commit adds a small bit of handling
to account for this so that the Router's transition does not advance
to the next stage until the URL has been committed.
2026-01-06 16:10:56 -05:00
Andrew Scott dd58c4b667 refactor(common): Add token to indicate whether precommit handler is supported
This commit adds a token that indicates whether the precommitHandler feature
is supported by the navigation api.

https://developer.mozilla.org/en-US/docs/Web/API/NavigateEvent/intercept#precommithandler
2026-01-06 16:10:56 -05:00
Andrew Scott 39efb62c0f fix(router): Ensure createUrlTree does not reuse segments of input
Mutating the `UrlTree` that is returned by `createUrlTree` can cause the
input, which might even be an active route, to be mutated. This ensures
the `UrlSegment`s are recreated and do not mutate the input.

fixes #54624
2026-01-06 13:11:54 -05:00
Andrew Scott db470f0881 refactor(router): Remove internal rxjs recognize implementation
All uses of this have been removed internally and it's no longer needed
2026-01-06 10:13:19 -05:00
Andrew Scott 5edceffd04 feat(router): add controls for route cleanup
This commit introduces a new feature to automatically destroy `EnvironmentInjector`s associated with routes that are no longer active or stored. This helps in managing memory by releasing resources held by unused injectors.
2026-01-05 14:43:56 -05:00
SkyZeroZx 712d8f41e8 refactor(router): Simplifies unsubscribe logic
Uses optional chaining to simplify unsubscribe handling.
Also improving tree-shaking by limiting injector names to route paths using `ngDevMode`
2026-01-05 12:08:08 -05:00
SkyZeroZx 004813dc37 docs: use currentNavigation instead of deprecated getCurrentNavigation 2026-01-02 08:25:43 +01:00
Matthieu Riegler 6270bba056 ci: reformat files
This is after we've slightly changed a rule in #66056
2025-12-16 14:44:19 -08:00
Anuj Chhajed 96b79fc393 refactor(core): correct all typeof ngDevMode comparison patterns introduced by #63875
This change replaces all remaining occurrences of `typeof ngDevMode !== undefined`
with the correct `typeof ngDevMode !== 'undefined'` form. This aligns the codebase
with JavaScript typeof semantics and maintains consistency with other Angular code.
2025-12-08 10:30:01 -08:00
Andrew Scott 37598cf6fe refactor(router): Adjust push/replace behavior to account for navigation API timing issues
There is a bug (?) in all browsers where the timing of the entry change
is delayed when a navigation is initiated by a click on a link via user
interaction. In this case, we need to ensure we do a 'push' navigation
rather than a 'replace'.
Programatically doing element.click() does not reproduce
this behavior, so adding a test for this is difficult (would require
webdriver).
2025-12-04 11:29:38 -08:00
arturovt b74a0693f2 fix(router): handle errors from view transition finished promise
This commit adds a `.catch()` handler to `transition.finished` from `document.startViewTransition` to prevent unhandled promise rejections. The finished promise can reject with `TimeoutError` or `InvalidStateError` when transitions fail during or after the animation phase.

Based on the Blink source code, the `finished` promise can reject with:
* `TimeoutError`: "Transition was aborted because of timeout in DOM update"
* `InvalidStateError`: "Transition was aborted because of invalid state"

This may happen when the DOM update phase exceeds the browser's internal timeout threshold.
2025-12-03 12:16:57 +01:00
Andrew Scott a0ad5d4b2b test(router): Add tests for support of path params before/after a wildcard
This adds additional tests following the initial implementation in #64737 that cover
the use-case of path parameters before and after the wildcard segment.
2025-12-02 16:46:17 +01:00
Andrew Scott fd65dc5d53 refactor(router): add comment about scroll/focus
Add consideration for future behavior in the completion of the navigation event.
2025-12-02 16:45:17 +01:00
Andrew Scott cc03254b12 refactor(router): Avoid aborting traversal navigations
Unnecessarily aborting traversal navigations will break focus and scroll
restoration. We need to keep them open rather than replacing them with
an identical router-initiated navigation.
2025-12-02 16:45:17 +01:00
Andrew Scott 9914926b0d refactor(router): Clean up cancellation event handling
cleans up some handling of cancellation events with a shared helper.
2025-12-02 16:45:17 +01:00
Andrew Scott b7d21e209a refactor(router): compress synchronous end to router navigation to single operator
The end of the Router navigation is a block of synchronous logic that
can be compressed into a single operator rather than splitting it across
several, making it harder to step through. The only benefit from the
split is automatic unsubscribe/cancellation, which we can replicate
with an additional 'shouldContinue' check before proceeding.
2025-12-02 16:44:01 +01:00
Tim Deschryver 680de24c3c docs: fix documentation link for currentNavigation method 2025-12-02 12:02:24 +01:00
SkyZeroZx 2ac826867b docs: Update router docs to add references and components input fixed syntaxis 2025-11-24 13:18:28 -05:00
Alessio Pelliccione 7d20f2071c docs(docs-infra): fix missing syntax highlighting
closed angular#65565
2025-11-24 13:13:22 -05:00
Andrew Scott 1ab461c846 refactor(router): Store route injector on ActivatedRoute instance
This eliminates the need to pass around the EnvironmentInjector
everywhere we need the injection context for a route.
2025-11-20 17:05:10 -05:00
Andrew Scott c25d749d85 feat(router): Execute RunGuardsAndResolvers function in injection context
Allows more sophisticated checks based on information available in DI
(e.g. the router state). Use-cases have been described in #53944 / https://github.com/angular/angular/issues/31843#issuecomment-1890955590

resolves #53944
2025-11-20 17:05:10 -05:00
Shuaib Hasan Akib c7affdfbc9 refactor(common): update examples to align with Angular best practices
Updated examples to use the standalone component approach and the latest
2025-11-19 14:29:49 -08:00
SkyZeroZx 718eb7bb3a docs: adds guide references to router APIs
Adds `@see` tags with links to relevant guides in the router documentation.
2025-11-13 10:00:19 -08:00
Alan Agius 4ed8781301 refactor(core): improve resource loading with async/await
Refactor  to use async/await for clearer asynchronous operations and enhanced error handling.
Simplify resource caching and streamline the resolution of component templates and styles.
Update  in the router to align with the new async resource resolution.
2025-11-11 12:50:16 -08:00
Shuaib Hasan Akib b0b834d7f1 refactor(router): add ngDevMode guards to InjectionToken names and cleanup imports
Wraps InjectionToken names with `typeof ngDevMode !== 'undefined' && ngDevMode`
checks to enable tree-shaking of descriptive token names in production builds.
This ensures debug-only strings are removed from production bundles, reducing size.

Also removes unused imports found during refactor.
2025-11-10 12:04:31 -08:00
arturovt d3f67f6ca8 refactor(core): mark VERSION as @__PURE__ for better tree-shaking
Annotate the `new Version(...)` call with `/* @__PURE__ */` to signal to optimizers that the constructor is side-effect free.

Without this hint, bundlers such as Terser or ESBuild may conservatively retain the `VERSION` instantiation even when unused. With the annotation, the constant can be tree-shaken away in production builds if not referenced, reducing bundle size.
2025-11-10 12:04:04 -08:00
arturovt 7724a9460d refactor(router): replace Optional with inject() flags
Replace `@Optional() link: RouterLink` constructor parameter with
`link = inject(RouterLink, {optional: true})` to enable tree-shaking
of the `Optional` decorator and its factory scaffolding.

Bundle size reduction: `Optional` is a runtime value created by
`makeParamDecorator()`. Even in production builds, ESBuild and other
bundlers must keep their factory code because it is referenced via
`Optional`. With `inject()`, this class is no longer referenced,
allowing it and the `makeParamDecorator` scaffolding to be tree-shaken
when unused elsewhere.

Note: This updates the constructor signature but should not be
considered a breaking change. Angular's official guidance is that
directives, components, and pipes should be instantiated by the
framework, not by user code. Directly calling `new RouterLinkActive(...)`
is an unsupported pattern that goes against Angular's design principles.
2025-11-10 09:48:32 -08:00
Andrew Scott 2db8f2ee75 refactor(router): Add handling of abort event on signal of NavigateEvent
This adds handling of the abort event on the signal of the
`NavigateEvent`, allowing us to cancel the Router's ongoing navigation
transition when its related navigation was aborted.
2025-11-10 08:02:43 -08:00
Andrew Scott 1651908004 refactor(router): Add handler to NavigationInterceptOptions
This adds a handler to the `NavigationInterceptOptions` when we are
intercepting a `NavigateEvent`. This means that the scroll and focus
restoration will be delayed until the handler promise resolves. It also
means that we can provide better indication of an ongoing navigation
event.
2025-11-07 13:32:49 -08:00
Andrew Scott 85d9abb019 refactor(router): Intercept navigate events (unless it's a rollback)
This adds further integration with the browser Navigation API by intercepting the navigation events.
2025-11-06 15:00:08 -08:00
Alan Agius 26fed34e0e build: format md files
This commit configures prettier to format markdown files.
2025-11-06 10:03:05 -08:00
SkyZeroZx 08a84e03e6 refactor(router): simplify imports and improve option access in RouterScroller tests
Simplifies imports and unifies option access in RouterScroller specs for cleaner and more consistent code
2025-11-06 09:42:41 -08:00