401 Commits

Author SHA1 Message Date
Andrew Scott 09a42d988e fix(router): canceledNavigationResolution: 'computed' with redirects to the current URL (#49793)
The `canceledNavigationResolution: 'computed'` option does not correctly
assign page IDs or restore them when redirects result in navigating to
the current URL. This change ensures that the page IDs are still
incremented and restored correctly in this scenario.

PR Close #49793
2023-04-14 14:55:06 +00:00
Andrew Scott cad7274ef9 fix(router): create correct URL relative to path with empty child (#49691)
The previous fix for squashing empty children didn't quite work when the
existing route had segments. The result would be that the segments from
the existing route were dropped from the final URL.

PR Close #49691
2023-04-04 15:05:42 -07:00
Andrew Scott 9b61379096 fix(router): Ensure initial navigation clears current navigation when blocking (#49572)
The navigation transition clears the current navigation in the finalize
operator of the current navigation Observer. This commit both completes
the `bootstrapDone` observable and updates the transition to only take 1
emit from the completed navigation. Either of these changes on their own
would fix the issue. The latter is a preventative measure in case a
mistake like the former is made again.

fixes #49567

PR Close #49572
2023-03-31 17:04:02 -07:00
Andrew Scott 978d37f324 fix(router): Ensure Router preloading works with lazy component and static children (#49571)
The preloading strategy did not handle a `loadComponent` on a route with
a static `children`. It only preloaded children if they were also
`loadChildren` or both were not lazy loaded.

fixes #49558

PR Close #49571
2023-03-24 10:41:11 -07:00
Jan Cabadaj a844435514 fix(router): fix #49457 outlet activating with old info (#49459)
Avoid activating outlet with old info if route was changed before outlet activated

PR Close #49459
2023-03-22 14:41:43 -07:00
Iván Navarro 3062442728 fix(router): add error message when using loadComponent with a NgModule (#49164)
Add a more specific error message when defining a lazy-loaded route using
`loadComponent` and passing it a NgModule instead of a standalone component,
when the user should actually be using `loadChildren`.

PR Close #49164
2023-02-27 10:09:55 -08:00
Matthieu Riegler 16ef770db8 fix(router): Handle routerLink directive on svg anchors. (#48857)
On svgs, the tagNames are lowercase even for non-svg related tags like `a`.

fixes #48854

PR Close #48857
2023-02-02 09:38:06 -08:00
Andrew Scott 4dcab333ae fix(router): 'createUrlTreeFromSnapshot' with empty paths and named outlets (#48734)
The details of this commit are pretty thoroughly described in the tests
and code comments. In short, it is sometimes ambiguous where to apply commands in
a `SegmentGroup` tree that is created from an `ActivatedRoute` when
dealing with empty paths. This adjusts the strategy to tolerate more
ambiguity while still allowing developers to be explicit.

This is a fix-forward for b/265215141

PR Close #48734
2023-01-18 10:46:43 -08:00
Andrew Scott b5137d82cc test(router): update createUrlTree tests to not use mocks (#48734)
The mocks in the tests make them hard to understand and they don't always test real router behavior

PR Close #48734
2023-01-18 10:46:43 -08:00
Andrew Scott 31b94c762f feat(router): Add a withNavigationErrorHandler feature to provideRouter (#48551)
`withNavigationErrorHandler` is a close replacement for the
`RouterModule.forRoot.errorHandler` / `Router.errorHandler`.
It provides a quick, short way for users to define a function to handle
`NavigationError` events.

PR Close #48551
2023-01-05 14:49:00 -08:00
Paul Gschwendtner 3d6cdd6aaa refactor: update packages/router tests to be compatible with ESM (#48521)
The ESM js files need to be referenced, and the router tests rely
on `async/await` with change detection- so a special rule is required
that downlevels `async/await` to generators (similar to the Angular CLI)

PR Close #48521
2022-12-19 19:50:43 +00:00
Paul Gschwendtner c9415e4d75 build: ensure bootstrap transitive runfiles are made available (#48521)
Since we generate a `.mjs` file as entry-point for jasmine tests,
a couple of issues prevented the transitive dependencies from
bootstrap targets to be brought in (causing resolution errors):

1. The `_files` (previously `_esm2015`) targets are no longer needed,
   and they also miss all the information on runfiles.
2. The aspect for computing linker mappings does not respect the
   `bootstrap` attribute from the `spec_entrypoint` so we manually
   add the extract ESM output targets (this rule works with the aspect
   and forwards linker mappings).

PR Close #48521
2022-12-19 19:50:41 +00:00
Paul Gschwendtner 20551503fa build: replace _es2015 shorthand with more flexible _files suffix (#48521)
For every `ts_library` target we expose a shorthand that grants
access to the JS files because `DefaultInfo` of a ts library
only exposes the `.d.ts` files.

We rename this away from `es2015` since in practice it's a much
higher target these days. Additionally we no longer use the devmode
output but rather use the prodmode output which has the explicit
`.mjs` output- compatible with ESM.

PR Close #48521
2022-12-19 19:50:41 +00:00
Matthieu Riegler 0fa70dfb6d refactor(router): code cleaning (#48259)
Removing unnecessary type assertions, null assertions etc.

PR Close #48259
2022-12-09 09:59:20 -08:00
Andrew Scott 6810a04143 refactor(router): Move events subject to transition class (#48202)
The events observable is part of the lifecycle of a navigation. This should
be contained in the NavigationTransitions class rather than the Router.
This Subject is re-exported by the router as an observable to maintain
the public API

PR Close #48202
2022-11-29 14:55:25 -08:00
Andrew Scott db1c73c431 Revert "refactor(router): Move events subject to transition class (#48202)" (#48269)
This reverts commit f555050f9a.

PR Close #48269
2022-11-28 16:52:07 -08:00
Matthieu Riegler dac5860a47 refactor(router): remove non-null assertions (#48244)
As part of #24571, removing non-null assertions (where appropriate)

PR Close #48244
2022-11-28 13:07:59 -08:00
Andrew Scott f555050f9a refactor(router): Move events subject to transition class (#48202)
The events observable is part of the lifecycle of a navigation. This should
be contained in the NavigationTransitions class rather than the Router.
This Subject is re-exported by the router as an observable to maintain
the public API

PR Close #48202
2022-11-28 10:53:26 -08:00
Andrew Scott 332461bd0c feat(router): Add ability to override onSameUrlNavigation default per-navigation (#48050)
The router providers a configurable `onSameUrlNavigation` value that
allows developers to configure whether navigations to the same URL as
the current one should be processed or ignored. However, this only acts
as a default value and there isn't an API for easily overriding this for
a single navigation. Instead, developers are forced to update the value
of the property on the router instance and remember to reset it.

This feature fills a small gap in the Router APIs that enables
developers to accomplish the task of force reloading a bit easier.

Lengthy discussion about this here: #21115

PR Close #48050
2022-11-22 19:20:33 -08:00
Andrew Scott 3c6a439a6f refactor(router): extract navigation transition code to a new file (#48092)
This commit extracts the Router's navigation "transitions" to a separate
file. The goal here is twofold:

- Separate the Router's logic into more manageable chunks. Rather than
  having to always edit a 1000+ line file, this separates different
  pieces into smaller, more focused files
- More importantly, this sets the groundwork for separating the Router
  state from the individual navigation transition. That is, it would be
  good for the rxjs pipeline to _not_ modify the Router state but only
  keep track of its own intermediate stages and emit outwards during
  important events. The Router can subscribe to those events and make
  updates to its state. This would theoretically allow us to swap those
  implementations independently. That is, the Router's state management
  can be changed without changing the transition handling and
  vice-versa.

PR Close #48092
2022-11-22 16:19:44 -08:00
Andrew Scott bc148c30d5 refactor(router): Remove unnecessary logic in enabledBlocking option (#48064)
The `initNavigated` flag is not necessary. The way `enabledBlocking`
works is by blocking any navigations from finishing until the
application has bootstrapped. The bootstrap is unblocked as soon as we
hit the `afterPreactivation` step. After that point,
`afterPreactivation` is always unblocked because the `bootstrapDone`
Subject is completed/stopped. There is no need for an additional
variable to track this information.

PR Close #48064
2022-11-22 11:36:14 -08:00
Andrew Scott 73f03ad2d2 feat(router): Add new NavigationSkipped event for ignored navigations (#48024)
The Router currently silently ignores navigations for two reasons:

1. By default, same URL navigations are ignored. When this situation is
   encountered, the navigation is ignored without any events
2. A `UrlHandlingStrategy` may ignore some URLs. For situations when the
   strategy returns `false` for `shouldProcessUrl`, the Router silently
   ignores the URL and updates its internal state without running
   matching, guards, or resolver logic.

This commit adds new `NavigationSkipped` events for the above two situations.

PR Close #48024
2022-11-22 11:34:49 -08:00
Andrew Scott ffc427bffc test(router): Update flaky tests to consistently pass (#48176)
This commit makes several updates to the bootstrap tests of the Router.
The change that made the real difference was providing
`MockPlatformLocation`. Other changes include:

* using `async/await` instead of `done`
* not providing APP_BASE_HREF (recent router refactors made this unnecessary)
* using some functional guards to simplify some tests

PR Close #48176
2022-11-22 11:33:18 -08:00
Nebojsa Cvetkovic 1976e37475 fix(router): restore 'history.state' on popstate even if navigationId missing (#48033)
If `history.pushState()` or `history.replaceState()` were called manually without including the `navigationId` field the state was being incorrectly discarded - that logic was for maintaining the original behavior of `NavigationStart.restoredState`.

Improves on #28176, fully fixes #28108, see also #28954

PR Close #48033
2022-11-21 13:46:17 -08:00
Andrew Scott 1df0ed7d6e fix(router): Ensure renavigating in component init works with enabledBlocking (#48063)
The way to complete the `Subject` in a way that is able to be read on
the subject properties itself is to call `unsubscribe`:
https://github.com/ReactiveX/rxjs/blob/afac3d574323333572987e043adcd0f8d4cff546/src/internal/Subject.ts#L101-L104
This sets the `closed` property to `true` whereas `complete` does not.

fixes #48052

PR Close #48063
2022-11-17 11:01:13 -08:00
Andrew Scott 2ae36142a6 test(router): Move test for redirect under correct describe block (#47993)
This moves a redirect test to be grouped with other redirect tests.

PR Close #47993
2022-11-08 10:34:21 -08:00
Andrew Scott 99898f3370 refactor(router): Remove code to support relativeLinkResolution (#47933)
The public API for enabling this option has already been removed. This change
updates the internal Router code to not include any logic to support it.

PR Close #47933
2022-11-07 09:26:19 -08:00
Albert Szekely 2ed5aeffd8 fix(router): fix redirectTo on named outlets - resolves #33783 (#47927)
fix(router): fix redirectTo on named outlets - resolves #33783

PR Close #47927
2022-11-04 09:30:29 -07:00
Andrew Scott bc0fc02016 refactor(router): Warn when provideRoutes is used without provideRouter (#47896)
Due to being only 1 letter away from `provideRouter`, it is quite
possible that developers may accidentally use `provideRoutes` rather
than `provideRouter` in the `boostrapApplication` function. This change
will warn developers when `provideRoutes` is used without the `Router`.

PR Close #47896
2022-11-04 09:29:24 -07:00
Andrew Scott 6b659d08ef docs(router): deprecate provideRoutes function (#47896)
This function is too similar in name to the new `provideRouter` and can
lead to misconfiguring the router. The function itself is just a small
wrapper around `{provide: ROUTES, multi: true, useValue: routes}`. It is
rarely necessary to provide routes in this way. The harm `provideRoutes`
will cause due to being only 1 letter away from `provideRouter` vastly
outweighs the benefit of a slightly shorter provider.

PR Close #47896
2022-11-04 09:29:24 -07:00
Andrew Scott af8afee5bd fix(router): Delay router scroll event until navigated components have rendered (#47563)
Currently, the scroll event is fired immediately after the
`NavigationEnd`. However, this is problematic because a change detection
has not been able to run, meaning that Angular will not yet have run the update
block of the component templates being rendered as part of the navigation.

This change delays the scroll event using a `setTimeout`, which will
allow Angular's change detection to run before the scroll restoration is
performed.

fixes #24547

PR Close #47563
2022-10-19 23:11:17 +02:00
Andrew Kushnir c0c7efaf7c feat(common): add provideLocationMocks() function to provide Location mocks (#47674)
This commit adds the `provideLocationMocks()` function that returns mocks for the `Location` and `LocationStrategy` classes. This function can be used in tests to configure an environment where it's possible to fire simulated location events (helpful when testing Router configuration).

PR Close #47674
2022-10-10 19:42:11 +00:00
Andrew Kushnir f73ef21442 feat(router): merge RouterLinkWithHref into RouterLink (#47630)
This commit updates the `RouterLink` to extend the selector to also include `<a>` and `<area>` elements, which were previously matched by the `RouterLinkWithHref` directive. The code of the directives was merged together (since there was a lot of duplication) and this commit finalizes the merge. The `RouterLinkWithHref` becomes an alias of the `RouterLink` directive.

Now there is no need to import and use the `RouterLinkWithHref` class, the `RouterLink` directive will match any element that has the `routerLink` attribute.

DEPRECATED:

The `RouterLinkWithHref` directive is deprecated, use the `RouterLink` directive instead. The `RouterLink` contains the code from the `RouterLinkWithHref` to handle elements with `href` attributes.

PR Close #47630
2022-10-05 15:16:43 -07:00
Andrew Scott 7b89d95c0e fix(router): Remove deprecated relativeLinkResolution (#47623)
The `relativeLinkResolution` is no longer supported. The only behavior
now is the correct behavior.

BREAKING CHANGE: `relativeLinkResolution` is no longer configurable in
the Router. This option was used as a means to opt out of a bug fix.

PR Close #47623
2022-10-05 08:57:28 -07:00
Andrew Scott 2f0761000f test(router): Ensure change detection runs after navigation (#47629)
Components are not fully rendered until change detection runs.

PR Close #47629
2022-10-04 16:19:32 -07:00
Alex Rickabaugh da58801f95 feat(router): auto-unwrap default exports when lazy loading (#47586)
When using `loadChildren` or `loadComponent`, a common pattern is to pass
a function that returns a `Promise` from a dynamic import:

```typescript
{
  path: 'lazy',
  loadComponent: () => import('./lazy-file').then(m => m.LazyCmp),
}
```

The `.then` part of the expression selects the particular exported
component symbol from the dynamically imported ES module.

ES modules can have a "default export", created with the `export default`
modifier:

```typescript
@Component({...})
export default class LazyCmp { ... }
```

This default export is made available to dynamic imports under the well-
known key of `'default'`, per the ES module spec:
https://tc39.es/ecma262/#table-export-forms-mapping-to-exportentry-records

This commit adds a feature to the router to automatically dereference such
default exports. With this logic, when `export default` is used, a `.then`
operation to select the particular exported symbol is no longer required:

```typescript
{
  path: 'lazy',
  loadComponent: () => import('./lazy-file'),
}
```

The above `loadComponent` operation will automatically use the `default`
export of the `lazy-file` ES module.

This functionality works for `loadChildren` as well.

PR Close #47586
2022-10-04 14:40:58 -07:00
Andrew Scott c3f857975d feat(router): make RouterOutlet name an Input so it can be set dynamically (#46569)
This commit updates the 'name' of `RouterOutlet` to be an `Input` rather
than an attribute. Note that this change does not affect `[attr.name]=`
because those already would not have worked. The static name was only
read in the constructor and if it wasn't available, it would use
'PRIMARY' instead.

fixes #12522

BREAKING CHANGE: Previously, the `RouterOutlet` would immediately
instantiate the component being activated during navigation. Now the
component is not instantiated until the change detection runs. This
could affect tests which do not trigger change detection after a router
navigation. In rarer cases, this can affect production code that relies
on the exact timing of component availability.

PR Close #46569
2022-10-04 07:57:25 -07:00
Andrew Scott 6a88bad019 fix(router): Ensure ActivatedRouteSnapshot#title has correct value (#47481)
ActivatedRouteSnapshot data gets mutated in the resolve phase of the Router. The title is assigned as part of this.
As a result, the title must be a getter in order to pick up the value that was note available during the class creation.

fixes #47459

BREAKING CHANGE: The title property is now required on ActivatedRouteSnapshot

PR Close #47481
2022-09-27 10:49:54 -07:00
Andrew Scott 75df404467 feat(router): Create APIs for using Router without RouterModule (#47010)
This commit creates and exposes the APIs required to use the Angular Router without importing `RouterModule`.

The newly added APIs are tree-shakable and you can add features using special functions rather than using `ExtraOptions` to control the providers via an internal switch in Router code.

```
const appRoutes: Routes = [];
bootstrapApplication(AppComponent,
  {
    providers: [
      provideRouter(appRoutes,
        withDebugTracing(),     // enables debug tracing feature
        withInMemoryScrolling() // enables scrolling feature
    ]
  }
);
```

This "features" pattern allows for router behavior to evolve in a backwards compatible and tree-shakable way in the future. This approach also makes features more discoverable.

The newly added APIs can be used in any application today (doesn't require an application to be bootstrapped using standalone-based APIs).

Note: APIs added in this commit are released in the "Developer Preview" mode, read more about this mode in Angular docs: https://angular.io/guide/releases#developer-preview

PR Close #47010
2022-08-15 15:58:00 -07:00
Emmanuel Roux 422323cee0 feat(router): improve typings for RouterLink boolean inputs (#47101)
Add wider typings to setter of preserveFragment, skipLocationChange and replaceUrl inputs of routerLink directives and coerce them to boolean

PR Close #47101
2022-08-12 13:28:38 +00:00
Andrew Scott 93289f9c76 refactor(router): Update error message when Router is provided twice (#47130)
The current error message is absolute in that it thinks there is only
one possible way to provide Router twice. In fact, you can get a new
instance of the Router in several ways so the error message should
indicate the exact failure case with a _potential_ cause.

Based on findings in thread https://github.com/angular/angular/commit/0cbbd6aeecda8ea994f1086727e580b813a53d79#commitcomment-80900192

PR Close #47130
2022-08-12 13:27:49 +00:00
Andrew Scott 0abb67af59 feat(router): allow guards and resolvers to be plain functions (#46684)
The current Router APIs require guards/resolvers to be present in the DI tree. This is because we want to treat all guards/resolvers equally and some may require dependencies. This requirement results in quite a lot of boilerplate for guards. Here are two examples:

```
const MY_GUARD = new InjectionToken<any>('my_guard');
…
providers: {provide: MY_GUARD, useValue: () => window.someGlobalState}
…
const route = {path: 'somePath', canActivate: [MY_GUARD]}
```

```
@Injectable({providedIn: 'root'})
export class MyGuardWithDependency {
  constructor(private myDep: MyDependency) {}

  canActivate() {
    return myDep.canActivate();
  }
}
…
const route = {path: 'somePath', canActivate: [MyGuardWithDependency]}
```

Notice that even when we want to write a simple guard that has no dependencies as in the first example, we still have to write either an InjectionToken or an Injectable class.

With this commit router guards and resolvers can be plain old functions.
 For example:

```
const route = {path: 'somePath', component: EditCmp, canDeactivate: [(component: EditCmp) => !component.hasUnsavedChanges]}
```

Additionally, these functions can still use Angular DI with `inject` from `@angular/core`.

```
const route = {path: 'somePath', canActivate: [() => inject(MyDependency).canActivate()]}
```

PR Close #46684
2022-08-05 10:36:46 -07:00
Andrew Scott d8cf78ba5e fix(router): Do not call preload method when not necessary (#47007)
In Angular 14, we introduced the `loadComponent` API for a `Route` to
allow lazy loading of a routed component in addition to the existing
`loadChildren` which allows lazy loading of child routes. As a result,
the `preload` method of the `PreloadingStrategy` needs to sometimes be
called even when there is a `canLoad` guard on the `Route`. `CanLoad`
guards block loading of child routes but _do not_ block loading of the
component.

This change updates the conditional checks in the internal preloader to
skip calling the `PreloadingStrategy.preload` when there is only a
`loadChildren` callback with a `canLoad` guard an no `loadComponent`.
In this case, the callback passed to the `preload` method is already
effectively a no-op so it's not necessary to call it at all.

resolves #47003

PR Close #47007
2022-08-02 09:38:28 -07:00
Emmanuel Roux 10289f1f6e feat(router): expose resolved route title (#46826)
Expose resolved route title from ActivatedRoute and ActivatedRouteSnapshot

PR Close #46826
2022-07-21 09:24:56 +00:00
Andrew Kushnir 7a6509bdc1 refactor(core): NgModuleRef should not implement EnvironmentInjector interface (#46896)
This commit refactors the `NgModuleRef` implementation to drop functions required by the `EnvironmentInjector` interface. Previously the idea was that the `NgModuleRef` can act as an Injector to facilitate easier transition to standalone. However, from the mental model perspective, the `NgModuleRef` has the `injector` field, which is the correct injector reference and can be used is needed as an `EnvironmentInjector`.

PR Close #46896
2022-07-20 08:49:15 -07:00
Paul Gschwendtner d2b444a8a2 test: update tests to account for karma-jasmine v5.0.0
Karma jasmine updated the `jasmine-core` dependency. Jasmine is now more
strict when:

* The done callback is invoked multiple times
* The done callback is used, while a promise is also returned
* The done callback is treated as error when e.g. a number is returned
  as first argument. This was the case with `requestAnimationFrame`.
2022-07-18 19:19:00 +02:00
Andrew Scott c0f023f602 fix(router): Ensure target RouterStateSnapshot is defined in NavigationError (#46842)
The Router transition observable pipe keeps an outer reference to a `t`
variable for use in the `catchError` operator. However, this variable is
not updated with intermediate state. This commit fixes that so the
`catchError` can access properties that get updated in intermediate
states. Specifically, `RouterStateSnapshot` in the `NavigationError` for
now but could be more in the future.

PR Close #46842
2022-07-14 22:19:26 +00:00
Andrew Scott bf5bee6d43 refactor(router): move around some code to eliminate circular deps (#46752)
This commit eliminates some circular dependencies by moving around
interfaces and type guards.

PR Close #46752
2022-07-11 17:59:31 +00:00
Andrew Scott e8ae0fe3e9 fix(router): Fix cancellation code for canLoad rejections (#46752)
Before this commit, the `NavigationCancellationCode` would always be set
to `Redirect` when encountering a "navigationcancelingError". However,
this error can also be thrown when `CanLoad` guars reject. This commit
ensures these cancellation errors have a code as well so this mistake
cannot be made again.

PR Close #46752
2022-07-11 17:59:30 +00:00
Andrew Scott 647afb02b3 refactor(router): Simplify the prioritizeGuardValue logic (#46745)
The existing logic does something similar but in a more roundabout way.
It reads _the whole array_. If it encounters a pending value, it ignores
the remaining ones. If it hasn't encountered a pending value by the time
it hits false/UrlTree, it returns that result.

The new logic is the same, but reverses what we're looking for. Instead
of processing the whole array, we stop when we encounter an initial
value. When we encounter one that isn't `true`, that gets returned. If
we get to the end and everything was `true`, return `true`.

PR Close #46745

PR Close #46745
2022-07-11 16:55:58 +00:00