Commit Graph

704 Commits

Author SHA1 Message Date
Andrew Scott 7b367d9d90 refactor(router): Remove unnecessary setTimeout in UrlTree redirects (#45735)
Using `setTimeout` in the Router navigation pipeline creates fragile and
unpredictable behavior. Additionally, it creates a new macrotask, which
would trigger an unnecessary change detection in the application.

This `setTimeout` was added in
https://github.com/angular/angular/commit/15e397816f98ec16839c30fd5c1ea01c7444fb84.
Both tests added in that commit still pass. Additionally, the comment
for _why_ the `setTimeout` was added doesn't really explain how the
described bug would occur. There has been a lot of work in the Router
since then to stabalize edge case scenarios so it's possible it existed
before but doesn't anymore.

Removing this `setTimeout` revealed tests that
relied on the navigation not completing. For example, the test suite did
not have a route which matched the redirect, but the test passed because
it ended before the redirect was flushed, so the `Router` never threw an
error. Similar situations exist for the other use of `setTimeout` in the Route
(the one in the location change listener).
There were no other failures in TGP other than incorrectly written
tests.

BREAKING CHANGE:
When a guard returns a `UrlTree`, the router would previously schedule
the redirect navigation within a `setTimeout`. This timeout is now removed,
which can result in test failures due to incorrectly written tests.
Tests which perform navigations should ensure that all timeouts are
flushed before making assertions. Tests should ensure they are capable
of handling all redirects from the original navigation.

PR Close #45735
2022-04-27 08:56:31 -07:00
Andrew Scott 50004c143b feat(router): Support lazy loading standalone components with loadComponent (#45705)
Similarly to the symmetry being strengthened between children and loadChildren,
a new loadComponent property will be introduced as the asynchronous version of component.
This will allow for direct single-component lazy loading:

```
{path: 'lazy/a', loadComponent:
  () => import('./lazy/a.component').then(m => m.ACmp)},
{path: 'lazy/b', loadComponent:
  () => import('./lazy/b.component').then(m => m.BCmp)},
```

This option requires that the component being loaded is standalone and
is implemented as a runtime check.

Other notes:
* Components are not loaded until all guards and resolvers complete.
* Loading the component is included in the function passed to the router
  preloading strategy
* `RouteConfigLoadStart` and `RouteConfigLoadEnd` events emit at the
  start and end of the component loading
* `CanLoad` guards _do not_ apply to `loadComponent`. `canActivate`
  should be used instead, just like you would do if it were simply
  `component` instead.

PR Close #45705
2022-04-25 09:39:44 -07:00
Andrew Scott 4962a4a332 feat(router): Allow loadChildren to return a Route array (#45700)
This commit expands the `LoadChildrenCallback` to accept returning `Routes`
in addition to the existing `NgModule` type. In addition, it adds a
check to ensure these loaded routes all use standalone components.
The components must be standalone because if they were not,
we would not have the required `NgModule` which the component is declared in.

Existing API:
```
{path: 'lazy/route', loadChildren: import('./lazy').then(m => m.LazyModule)}

@NgModule({
  imports: [
    ExtraCmpModule,
    RouterModule.forChild([
      {path: 'extra/route', component: ExtraCmp},
    ]),
  ],
})
export class LazyModule {}
```

The new API for lazy loading route configs with standalone components
(no NgModule) is to expand `loadChildren` to allow returning simply a `Routes` array.

```
// parent.ts
{
  path: 'parent',
  loadChildren: () => import('./children').then(m => m.ROUTES),
}

// children.ts
export const ROUTES: Route[] = [
  {path: 'child', component: ChildCmp},
];
```

Note that this includes minimal documentation updates. We need to
include a holistic update to the documentation for standalone components
in the future that includes this feature.

PR Close #45700
2022-04-22 09:25:20 -07:00
dario-piotrowicz dea8c86cd5 feat(router): add ariaCurrentWhenActive input to RouterLinkActive directive (#45167)
add the ariaCurrentWhenActive input to the RouterLinkActive directive so that
users can easily set the aria-current property to their active router
links

resolves #35051

PR Close #45167
2022-04-20 15:14:01 -07:00
Andrew Scott 1d2f5c1101 refactor(router): deprecate no longer needed resolver fields (#45597)
DEPRECATED:

The `resolver` argument of the `RouterOutletContract.activateWith` function and the `resolver` field of the `OutletContext` class are deprecated. Passing component factory resolvers are no longer needed. The `ComponentFactoryResolver`-related symbols were deprecated in `@angular/core` package since v13.

PR Close #45597
2022-04-20 12:57:37 -07:00
Andrew Scott f4fd1a8262 feat(router): Add EnvironmentInjector to RouterOutlet.activateWith (#45597)
The current API for `activateWith` uses the deprecated
`ComponentFactoryResolver`. The replacement for this is to use
`EnvironmentInjector`. That is, instead of

```
const factory = componentFactoryResolver.resolveComponentFactory(component);
location.createComponent(factory, location.length, injector);
```

the replacement would be

```
location.createComponent(
    component, {index: location.length, injector, environmentInjector});
```

PR Close #45597
2022-04-20 12:57:37 -07:00
Andrew Scott 4e0957a4e1 feat(router): Add ability to specify providers on a Route (#45673)
Currently, the only way to specify new providers for a `Route` and the
children is to create a new `NgModule` with those providers and use the
`loadChildren` feature. This is pretty confusing and a wholly indirect
way of accomplishing this task. With this commit, developers will be
able to specify a list of providers directly on the `Route` itself.
These providers will apply the that route and its children.

This feature was inspired by the upcoming standalone components feature.
This ties in there because, as mentioned before, the prior art for lazy
loading configs was to load an `NgModule`. This loaded module contained
new route configs _and_ could specify new providers. Separating those
two concepts, there should be a way to load _just_ some new routes, but
there should also be a way to specify new providers as well (something
you could do in the `NgModule` world and now will be able to do in the
world without any `NgModule` through this feature).

PR Close #45673
2022-04-20 11:32:07 -07:00
Andrew Scott 989e840cce fix(router): Remove unused string type for ActivatedRoute.component (#45625)
BREAKING CHANGE:
The type of `component` on `ActivatedRoute` and `ActivatedRouteSnapshot`
includes `string`. In reality, this is not the case. The component
cannot be anything other than a component class.

PR Close #45625
2022-04-19 20:21:35 -07:00
Andrew Scott ea8256f43d refactor(router): Move config loader tracking to the RouterConfigLoader (#45656)
This wasn't exactly possible before because the `RouterConfigLoader` was
not an Injectable so there wasn't a straightforward way to share
information between `ApplyRedirects` and the preloader. They each had
their own implementation so they needed to store the values on the
`Route` so they both had access to them. I imagine this was the case
because trying to inject `Router` (to get access to the events) into the
preloader would have caused a circular dependency.

This refactor co-locates the loading details with the loader itself
rather than leaking implementation into the public route config and
mutating the object in an awkward way. This also promotes
`RouterConfigLoader` to a proper `Injectable` so data can be shared
throughout the system.

PR Close #45656
2022-04-18 16:05:45 -07:00
Andrew Scott aa966fd715 refactor(router): Use EnvironmentInjector for lazy loading APIs (#45671)
The `EnvironmentInjector` should be used instead of `Injector` for the
lazy loading. A future refactor will further update `RouterOutlet` to
use this injector to create the component rather the deprecated
`ComponentFactoryResolver`.

PR Close #45671
2022-04-18 14:08:43 -07:00
Andrew Scott eb7661c072 refactor(router): unbundle the lazy loaded routes from the lazy loaded module injector (#45593)
In the standalone world, these concepts will no longer be one and the
same. You can load routes without them being inside an `NgModule` with
`RouterModule.forChild`. In addition, routes will be able to define
their own providers, which will be included in an injector that is not
necessarily lazy loaded.

PR Close #45593
2022-04-18 09:52:56 -07:00
Andrew Scott d9f550c97f refactor(router): Refactor loaded config to track injectors rather than NgModuleRef (#45593)
The `Injector` is really the piece of information that the `Router` is
interested in keeping track of. Storing the `NgModuleRef` is somewhat
confusing based on how it's used later on. `RouterOutlet` uses it for the
`componentFactoryResolver`, but this is not needed anymore (and deprecated). In
fact, we can get back to the `NgModuleRef` anyways using the injector.
For now, that's what this change does. A different refactor will remove
the use of the `componentFactoryResolver` altogether.

Additionally, in the standalone world, we plan to implement a feature to
allow defining `providers` directly on the `Route`. This means there
won't be an associated `NgModuleRef` so this refactor prepares for that
feature.

PR Close #45593
2022-04-18 09:52:56 -07:00
Andrew Scott 96fd29c6d2 fix(router): validate lazy loaded configs (#45526)
Lazy loaded configs are not validated at runtime like the initial set of
routes are. This change also validates lazy loaded configs right after
they're loaded.

BREAKING CHANGE: Lazy loaded configs are now also validated once loaded like the
initial set of routes are. Lazy loaded modules which have invalid Route
configs will now error. Note that this is only done in dev mode so
there is no production impact of this change.

Fixes #25431

PR Close #45526
2022-04-15 12:30:44 -07:00
Dmitrij Kuba f13295f3a3 perf(router): cancel the navigation instantly if at least one resolver doesn't emit any value (#45621)
Recently the navigation was on hold even at least one resolver didn't emit any value and completed, but another ones still are in progress to resolve any value. The changes cancel the navigation instantly if at least one resolver doesn't emit any value and completed.

PR Close #45621
2022-04-15 10:06:26 -07:00
Andrew Scott 000363eec5 refactor(router): combine functions for getting loaded config (#45613)
There are two functions which do the same thing and are meant to search
for the closest loaded config in the `ActivatedRouteSnapshot` parent
tree. These can be combined to reduce code duplication.

One difference in the current implementation is the early exit for the
implementation in `activate_routes` when `route.component` is defined.
This early exit takes advantage of the fact that the component must then
also have a `RouterOutlet`, which injects `ComponentFactoryResolver`,
which would end up being the same one as what would be found if we
continued to look up the parent tree. This is only a tiny optimization
that will actually break when we add `providers` as a feature to the
`Route` config. In this scenario, we _must_ find the correct injector
in the parent routes and cannot rely on a parent `RouterOutlet` since
there may be some route with a providers list in between.

PR Close #45613
2022-04-13 17:29:42 -07:00
Andrew Scott 47e7a2850b refactor(router): Add warning for relativeLinkResolution: 'legacy' (#45523)
This change adds code to compute the corrected value for a link,
regardless of the `relativeLinkResolution` value. Then, if the
`relativeLinkResolution` is set to `legacy` and differs from the correct
value, a warning is printed to the console in dev mode.

This change is meant to assist in notifying developers that they have
code which relies on the deprecated, broken behavior so they can fix and
update the code before the `relativeLinkResolution` option is fully
removed.

PR Close #45523
2022-04-13 17:19:08 +00:00
Jessica Janiuk d11d1c0b70 Revert "refactor(router): Add warning for relativeLinkResolution: 'legacy' (#45523)" (#45594)
This reverts commit d180db15bf.

PR Close #45594
2022-04-12 00:08:41 +00:00
Andrew Scott d180db15bf refactor(router): Add warning for relativeLinkResolution: 'legacy' (#45523)
This change adds code to compute the corrected value for a link,
regardless of the `relativeLinkResolution` value. Then, if the
`relativeLinkResolution` is set to `legacy` and differs from the correct
value, a warning is printed to the console in dev mode.

This change is meant to assist in notifying developers that they have
code which relies on the deprecated, broken behavior so they can fix and
update the code before the `relativeLinkResolution` option is fully
removed.

PR Close #45523
2022-04-11 20:51:15 +00:00
Andrew Scott f8f3ab377b fix(router): Remove any from LoadChildrenCallback type (#45524)
The `LoadChildrenCallback` type previously included `any` in the
possible return value union for `Promise`. This is too loose and should
be restricted to values that are actually supported.

BREAKING CHANGE: When returning a `Promise` from the
`LoadChildrenCallback`, the possible type is now restricted to
`Type<any>|NgModuleFactory<any>` rather than `any`.

PR Close #45524
2022-04-07 21:01:09 +00:00
Martin Sikora 1c11a57155 fix(router): merge interited resolved data and static data (#45276)
in layers

Right now route static data are collected from its parents based on the logic
described in `inheritedParamsDataResolve()`, merged into a single object
and then merged again with merged data from resolvers. This means that a
child's data can be overriden by a resolver in its parent (#34361).
However, what is the expected behavior is not described in the documentation.
This PR changes this behavior and merges static data and resolved data
in "layers" (route by route) so child's static data and resolved data
cannot be overriden by their parents.

Fixes #34361

PR Close #45276
2022-04-05 08:49:09 -07:00
Andrew Scott 96c7cc933e docs: deprecated relativeLinkResolution in the Router (#45308)
The `relativeLinkResolution` option was added as an option to opt-in to
corrected behavior when generating links relative to a route that has an
empty path parent. This was needed to avoid a breaking change. Since
then, we have switched the default to be the corrected behavior.
It's time to close the turn the lights off on this option so we no
longer have to maintain and document buggy behavior.

PR Close #45308
2022-03-25 16:50:46 -07:00
Tobias Speicher 4ddcf81e61 refactor: replace deprecated String.prototype.substr() (#45397)
.substr() is deprecated so we replace it with functions which work similarily but aren't deprecated

Signed-off-by: Tobias Speicher <rootcommander@gmail.com>

PR Close #45397
2022-03-24 11:48:09 -07:00
Mike 85782e607d docs(router): Fix typo on segments (#45411)
PR Close #45411
2022-03-24 10:49:35 -07:00
AlirezaEbrahimkhani 59a5b54c23 docs: add how to access the resolved data (#45345)
complete resolver example and add how to access the resolved data in component

resolves angular#45313

PR Close #45345
2022-03-16 15:05:24 -07:00
Andrew Scott a08ea3f643 refactor(router): Make a few adjustments to createUrlTree for clarity (#45306)
* `tree` function now accepts the old root rather than the old
  `UrlTree`. The `urlTree` argument was only used to get the `root`.
  This change makes it more clear what that pararmeter is used for and
  what's actually being used
* Move the `oldRoot` (previously `urlTree`) to be the first argument of `tree`.
  This change now mirrors the argument order for `replaceSegment` and
  can be read from left to right more easily "in this root,
  replace this old segment group with this new segment group".
* Extract `newRoot` to a variable. This just makes it more clear what's
  going on at the end rather than combining a bunch of operations into
  one.

These changes are being made so that hopefully a future refactor can be
done which does not rely on the `urlTree` argument at all in the
`createUrlTree` function. These refactorings will make it easier to see
1:1 functionlity in these various places.

PR Close #45306
2022-03-09 13:52:38 -08:00
Andrew Scott 26ead25df6 refactor(router): Use helper function to throw NoMatch (#45244)
This update matches the other locations where noMatch is thrown.

PR Close #45244
2022-03-04 15:24:13 -08:00
Andrew Scott 5883e0536c refactor(router): Remove special logic for hybrid apps (#45240)
This commit removes special (undocumented) logic in the Router code that is
meant to prevent duplicate navigations that result from location syncs in
AngularJS/Angular hybrid applications.

The duplicate navigations can occur when both the Router and the AngularJS sync
code detect a location change via a popstate/hashchange event. When this
happens, the Angular Router schedules a navigation to sync itself with
the browser, but the hybrid listener may also schedule an additional
navigation. There are a few reasons this logic should not be included in
the Router:

* This special logic is not tree shakeable so it introduces a bundle
  size cost for all applications, most of which don't need it.
* There have been many updates to the routing pipeline to tolerate
  duplicate navigations. That is, duplicate navigations can happen and
  routing should still complete successfully.
    * https://github.com/angular/angular/commit/0e8548f667e5fdefa3ac7cdf1ba47e3e17011ffc
    * https://github.com/angular/angular/commit/9e039ca68bfae5328f3fc1f16fabd7673c466a25
* The logic is really in the wrong place: The hybrid sync code should be
  the location to handle this. If duplicate navigations are meant to be
  avoided, the hybrid sync code should have handling to _not_ trigger
  duplicate navs.
* This logic _also_ used to exist because the mock location
  helper used for test incorrectly triggered popstate events during
  router navigations. In order to avoid unexpected behavior in tests, this
  logic needed to be added. This incorrect mocking may also have been
  put in place because the upgrade module _would_ see a location change
  event and trigger a duplicate navigation.  The location mock has since been updated to
  match real browser behavior so this is no longer necessary. The
  upgrade module has also been updated to not trigger duplicate
  navigations.  The following commits are related to this:
    * https://github.com/angular/angular/commit/202a1a56314af4ddb99c476f974536a10e390319
    * https://github.com/angular/angular/commit/c6a93001eb74374b0fbc6aea1286fe1183d21382

Side note: The `setTimeout` in the location change listener is used to
ensure the ordering of duplicate navigations was consistent. You can see
that the logic being removed here expects the imperative navigation to precede the
popstate/hashchange. With the removal of this code, the `setTimeout` no
longer serves a purpose. However, it has been found that tests can rely
on this behavior (incorrectly) because they expect the navigation to be
complete but in reality, it hasn't even started because the test has not
flushed the timeout. Removing the timeout would be a breaking change as
a result.

PR Close #45240
2022-03-03 09:14:39 -08:00
Dmitrij Kuba c9679760b2 refactor(router): take only the first emitted value of every resolver to make it consistent with guards (#44573)
The router used to wait for the resolvers to complete and take the last
value. The changes here take only the first
emitted value of every resolver and proceed the navigation. This matches
how other guards work in the `Router` code.

Resolves https://github.com/angular/angular/issues/44643

BREAKING CHANGE: Previously, resolvers were waiting to be completed
before proceeding with the navigation and the Router would take the last
value emitted from the resolver.
The router now takes only the first emitted value by the resolvers
and then proceeds with navigation. This is now consistent with `Observables`
returned by other guards: only the first value is used.

PR Close #44573
2022-03-01 17:12:37 +00:00
Andrew Scott 0920104372 refactor(router): Refactor errors in applyRedirects to use common throwError function (#45170)
The implementation of `throwError` in `rxjs` is identical to what is
done manually in the Router code.

PR Close #45170
2022-02-24 23:50:00 +00:00
Andrew Scott d8428ca598 refactor(router): Update match result to be more explicit (#45170)
The `lastChild` property in the match result is only used to compute the
remaining segments (i.e. the ones which were not consumed). The updated
type here makes it easier to use and more clear.

PR Close #45170
2022-02-24 23:50:00 +00:00
Andrew Scott 7fd416d060 fix(router): Fix type of Route.pathMatch to be more accurate (#45176)
Route.pathMatch only allows `'full'|'prefix'` in reality. This commit
adjusts the type to be more strict and also adds a migration to adjust
existing code.

resolves #37469

BREAKING CHANGE:
The type of `Route.pathMatch` is now more strict. Places that use
`pathMatch` will likely need to be updated to have an explicit
`Route`/`Routes` type so that TypeScript does not infer the type as
`string`.

PR Close #45176
2022-02-24 18:44:07 +00:00
Ruslan Lekhman d5719c2e0f fix(core): input coercion (#42803)
BREAKING CHANGE: Forms [email] input coercion

Forms [email] input value will be considered as true if it is defined with any value rather
than false and 'false'.

PR Close #42803
2022-02-07 10:52:59 -08:00
markostanimirovic 33df8405c9 docs(router): clarify execution order for resolvers (#44995)
Fixes #44971

PR Close #44995
2022-02-07 09:44:21 -08:00
Andrew Scott 64f837d2c0 fix(router): Update Navigation#initialUrl to match documentation and reality (#43863)
BREAKING CHANGE:

* The type of `initialUrl` is set to `string|UrlTree` but in reality,
  the `Router` only sets it to a value that will always be `UrlTree`
* `initialUrl` is documented as "The target URL passed into the
  `Router#navigateByUrl()` call before navigation" but the value
  actually gets set to something completely different. It's set to the
  current internal `UrlTree` of the Router at the time navigation
  occurs.

With this change, there is no exact replacement for the old value of
`initialUrl` because it was enver intended to be exposed.
`Router.url` is likely the best replacement for this.
In more specific use-cases, tracking the `finalUrl` between successful
navigations can also be used as a replacement.

PR Close #43863
2022-02-04 01:07:01 +00:00
markostanimirovic 791bd31424 feat(router): set stricter type for Route.title (#44939)
This commit changes the type of `Route.title` property from
`string | unknown` to `string | Type<Resolve<string>>`.

Fixes #44936

PR Close #44939
2022-02-03 12:40:28 -08:00
markostanimirovic 4dbd2028fe refactor(router): move types from config and interfaces to models (#44939)
This commit moves all types from `config.ts` and `interfaces.ts`
to `models.ts` to fix circular dependency.

PR Close #44939
2022-02-03 12:40:28 -08:00
Andrew Scott 202a1a5631 fix(upgrade): Do not trigger duplicate navigation events from Angular Router (#43441)
This code mimics behavior that Google Analytics has been using to
prevent duplicate navigations. They set up their own `HybridRoutingService`
location sync to avoid duplicate navigations that came from the Angular
router. This would happen because the Angular router would trigger a
navigation, which would then get picked up by the `$locationShim`, which
would trigger a `$locationChangeStart`, which would then be picked up by
the `setUpLocationSync` watcher here, which would again trigger a
navigation in the Angular Router.

All of this can be prevented by checking if the `navigationId` exists on
the history state object. This property is added by the Angular router
during navigations.

fixes #21610

PR Close #43441
2022-02-02 19:51:20 +00:00
markostanimirovic 4b4bf05ad4 docs(router): provide better typing for resolver example (#44932)
PR Close #44932
2022-02-01 22:06:29 +00:00
Andrew Scott fdfcef5a0a build: enable useUnknownInCatchVariables (#44679)
This unblocks the internal migration to turn the option on in g3.

PR Close #44679
2022-02-01 18:17:29 +00:00
Andrew Scott 910de8bc33 feat(router): Add Route.title with a configurable TitleStrategy (#43307)
This commit provides a service, `PageTitleStrategy` for setting
the document page title after a successful router navigation.

Users can provide custom strategies by extending `TitleStrategy` and
adding a provider which overrides it.

The strategy takes advantage of the pre-existing `data` and `resolve` concepts
in the Router implementation:

We can copy the `Route.title` into `data`/`resolve` in a
non-breaking way by using a `symbol` as the key. This ensures that we
do not have any collisions with pre-existing property names. By using
`data` and `resolve`, we do not have to add anything more to
the router navigation pipeline to support this feature.

resolves #7630

PR Close #43307
2022-01-27 22:02:33 +00:00
Wiley Marques 8363db4189 docs(router): fixing pathMatch doc to style code correctly (#44796)
PR Close #44796
2022-01-24 10:42:51 -08:00
Andrew Scott 5a4ddfd4f5 feat(router): Allow symbol keys for Route data and resolve properties (#44519)
This commit adds the ability to use a symbol as the key for the `data` and `resolve` objects
in a `Route` config.

PR Close #44519
2022-01-10 19:43:12 +00:00
Kristiyan Kostadinov 359103274b test: clean up more entryComponents usages (#44561)
Cleans up some more tests that were using `entryComponents`.

PR Close #44561
2022-01-06 18:36:22 +00:00
Chris Mancini 6a55affacd docs(router): fix code block for IsActiveMatchOptions (#44635)
PR Close #44635
2022-01-05 17:47:08 +00:00
unknown f44cb57c12 fix(router): prevent componentless routes from being detached (#44240)
Currently, when deactivating a route, the detach method of the RouteReuseStrategy is always called
even when we are dealing with a componentless route. If when using a custom strategy we attempt to
detach a componentless route, an exception is thrown causing the navigation to break.
This change prevents this from happening, by not triggering the detach of the route reuse strategy.

Fixes #44239

PR Close #44240
2021-11-23 17:12:27 +00:00
Martin von Gagern aac579d976 refactor(router): add type annotation for UrlSegment.parameterMap (#44175)
Having the type specified explicitly makes the API reference more readable.
PR Close #44175
2021-11-16 09:36:17 -08:00
Andrew Scott d015ac214f Revert "refactor(router): restore history in a consistent way on canceled navigations (#43651)" (#44006)
This reverts commit a268c4471f.

Causes failures in internal team's code. The failures likely relate to
attempting to manually update private Router state tracking properties,
which this change would have affected.

PR Close #44006
2021-11-01 09:25:36 -07:00
krzysztof-grzybek 45e4e60fd6 fix(router): reuse route strategy fix (#43791)
Currently, it's impossible to cache (detach/attach) parent route without caching child routes.
This produces a bug, when navigating from a/b to c, then to a/d, where a route is cached.
On the last navigation, we incorrectly restore a/b route instead of a/d.
This change introduces new behavior: if the route should be detached/attached,
we do so, but we check also child routes recursively.

Fixes #17333

PR Close #43791
2021-10-21 16:28:03 +00:00
Andrew Scott 32f368af2d fix(router): Do not clear currentNavigation if already set to next one (#43852)
Experimentation with the Router URL management exposed a situation where
the `currentNavigation` was being cleared in the `finalize` after the
`currentNavigation` was already set to the next one.

This change ensures that the `currentNavigation` is only cleared if the
id of the finalized transition matches the one on the
`currentNavigation` object.

PR Close #43852
2021-10-18 10:30:50 -07:00
Andrew Scott a3ee474897 refactor(router): Remove use of browserUrlTree in scheduleNavigation (#43632)
There are no added tests here because the change is generally equivalent
to what was there before. The goal of that piece of code is to prevent
duplicate navigations due to the location synchronization code between
AngularJS and Angular. That is, the Angular router listens to the
`popstate` event and triggers navigations, but so does the AngularJS
router and triggers navigations through `router.navigateByUrl`. The
`setTimeout` in the Angular Router's `setUpLocationChangeListener` is
there to make this bit of code work: the 'popstate'/'hashchange'
navigation will necessarily come after the imperative nav triggered by
AngularJS's location sync.

Anyhow, in the long run, I would like to get rid of this bit of code
altogether. We should not have special handling for these cases. The
AngularJS/Angular location sync should either:

1. Not trigger a duplicate navigation in the first place
or
2. Be tolerant to processing the duplicate navigation.

In the short term, this change benefits the router while we investigate
removing this logic completely because now browserUrlTree has a single
responsiblity: to support `onSameUrlNavigation==='reload'`. This means
that we can work towards removing the `browserUrlTree` tracking from the
Router code at some point as well and have the `onSameUrlNavigation`
logic be part of a pre-navigation hook that can be handled outside the
`Router`. This may or may not be possible, but the change here opens up
that change for investigation.

PR Close #43632
2021-10-18 10:29:22 -07:00