366 Commits

Author SHA1 Message Date
Andrew Scott aef353c143 fix(router): Ensure renavigating in component init works with enabledBlocking (#48066)
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 #48066
2022-11-15 21:40:13 +00:00
Andrew Scott 28efb06a96 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:22 -08:00
Albert Szekely db867fee77 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:31 -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
Andrew Scott e8c7dd10e9 fix(router): Ensure APP_INITIALIZER of enabledBlocking option completes (#46026)
Previously, if `initialNavigation` were set to `enabledBlocking`, the
Router's `APP_INITIALIZER` would never resolve if that initial
navigation failed. This results in the application load hanging and
never completing.

fixes #44355

PR Close #46026
2022-06-29 14:53:30 -07:00
Andrew Scott 36f46c6a9d refactor(router): Convert user-visible router errors to RuntimeError (#46562)
This commit refactors the Router errors to use the standard
`RuntimeError` used by the framework packages.

PR Close #46562
2022-06-29 12:50:23 -07:00
Andrew Scott ee39cf62bc fix(router): Ensure that new RouterOutlet instances work after old ones are destroyed (#46554)
There can be timing issues with removing an old outlet and creating a
new one to replace it. Before calling `onChildOutletDestroyed`, the
`RouterOutlet` will first check to ensure that it is still the one
registered for that outlet name.

Fixes #36711
Fixes #32453

PR Close #46554
2022-06-28 12:54:53 -07:00
Dmitrij Kuba abe3759e24 fix(router): allow to return UrlTree from CanMatchFn (#46455)
Currently it's not possible to return plain `UrlTree` from `CanMatchFn`,
only wrapped `UrlTree` into Observable or Promise is allowed.
These changes allow to return `UrlTree` from `CanMatchFn`.

PR Close #46455
2022-06-22 13:25:23 -07:00
Andrew Scott f94c6f433d fix(router): Expose CanMatchFn as public API (#46394)
The `CanMatchFn` is already exposed in the type signature for `canMatch` on the
`Route`. This function type should already be exposed as public API but was
missed in the initial implementation because the older guards use the `any` type
instead.

PR Close #46394
2022-06-17 09:18:08 -07:00
Andrew Scott ce20ed067f fix(router): Ensure Route injector is created before running CanMatch guards (#46394)
Once a `Route` matches via the `match` or `path` property, we need to
immediately create the injector for the route (if it has providers)
before running the `CanMatch` guards. This is necessary because the
`CanMatch` guards might be provided in the `Route` providers.

Fixes #46386

PR Close #46394
2022-06-17 09:18:08 -07:00
Andrew Scott 72e6a948bb refactor(router): Update recognize to use Observable instead of Promise (#46021)
The `Observable` chain is currenlty the most straightforward way to
handle navigation cancellations where we ensure that the cancelled
navigation does not continue to be processed. Until we design and
implement an alternative way to accomplish equivalent functionality,
we need to maintain the `Observable` chain wherever we might execute
user code. One reason for this isthat user code may contain redirects so we do not
want to execute those redirects if the navigation was already cancelled.

PR Close #46021
2022-06-13 22:53:49 +00:00
Andrew Scott de058bba99 feat(router): Add CanMatch guard to control whether a Route should match (#46021)
Currently we have two main types of guards:
`CanLoad`: decides if we can load a module (used with lazy loading)
`CanActivate` and friends. It decides if we can activate/deactivate a route.
So we always decide where we want to navigate first ("recognize") and create a new router state snapshot. And only then we run guards to check if the navigation should be allowed.
This doesn't handle one very important use case where we want to decide where to navigate based on some data (e.g., who the user is).
I suggest to add a new guard that allows us to do that.

```
[
  {path: 'home', component: AdminHomePage, canUse: [IsAdmin]},
  {path: 'home', component: SimpleHomePage}
]
```

Here, navigating to '/home' will render `AdminHomePage` if the user is an admin and will render 'SimpleHomePage' otherwise. Note that the url will remain '/home'.

With the introduction of standalone components and new features in the Router such as `loadComponent`,
there's a case for deprecating `CanLoad` and replacing it with the `CanMatch` guard. There are a few reasons for this:

* One of the intentions of having separate providers on a Route is that lazy
loading should not be an architectural feature of an application. It's an
optimization you do for code size. That is, there should not be an architectural
feature in the router to specifically control whether to lazy load something or
not based on conditions such as authentication. This is a slight nuanced
difference between the proposed canUse guard: this guard would control whether
you can use the route at all and as a side-effect, whether we download the code.
`CanLoad` only specified whether the code should be downloaded so canUse is more powerful and more appropriate.
* The naming of `CanLoad` will be potentially misunderstood for the `loadComponent` feature.
Because it applies to `loadChildren`, it feels reasonable to think that it will
also apply to `loadComponent`. This isn’t the case: since we don't need
to load the component until right before activation, we defer the
loading until all guards/resolvers have run.

When considering the removal of `CanLoad` and replacing it with `CanMatch`, this
does inform another decision that needed to be made: whether it makes sense for
`CanMatch` guards to return a UrlTree or if they should be restricted to just boolean.
The original thought was that no, these new guards should not allow returning UrlTree
because that significantly expands the intent of the feature from simply
“can I use the route” to “can I use this route, and if not, should I redirect?”
I now believe it should allowed to return `UrlTree` for several reasons:

* For feature parity with `CanLoad`
* Because whether we allow it as a return value or not, developers will still be
able to trigger a redirect from the guards using the `Router.navigate` function.
* Inevitably, there will be developers who disagree with the philosophical decision
to disallow `UrlTree` and we don’t necessarily have a compelling reason to refuse this as a feature.

Relates to #16211 - `CanMatch` instead of `CanActivate` would prevent
blank screen. Additional work is required to close this issue. This can
be accomplished by making the initial navigation result trackable (including
the redirects).
Resolves #14515
Replaces #16416
Resolves #34231
Resolves #17145
Resolves #12088

PR Close #46021
2022-06-13 22:53:49 +00:00
Andrew Scott caa2f3560d refactor(router): clean up internal hooks (#46321)
* beforePreactivation hook is unused
* The only place that uses afterPreactivation does not use the arguments

Not to say we won't want to provide hooks similar to this in the future,
but the current state is over-engineered for what it's being used for.

PR Close #46321
2022-06-10 15:23:57 +00:00
Andrew Scott 243c6797f4 test(router): illustrate canceling of intermediate results in canLoad (#46231)
This adds a test to illustrate the "canceling" behavior we get from the
`Observable` chain in the Router. A new navigation cancels ongoing ones,
and that means also preventing intermediate results in user guards from
executing. This test is important when thinking about future refactors
which might attempt to change the details of how the `applyRedirects`
operator executes.

PR Close #46231
2022-06-03 10:06:54 -07:00
Andrew Scott 53ca936366 feat(router): Add ability to create UrlTree from any ActivatedRouteSnapshot (#45877)
This exposes a new function from the router public API that allows
developers to create a `UrlTree` from _any_ `ActivatedRouteSnapshot`.
The current Router APIs only support creating a `UrlTree` from an
`ActivatedRoute` which is both active _and_ materially appears in the
`UrlTree` (it cannot be an empty path named outlet). This is because the
implementation of the current way of creating a `UrlTree` attempts to
look up the `UrlSegment` of the `ActivatedRoute` in the currently active
`UrlTree` of the router. When this doesn't work, the `UrlTree` creation
fails.

Note that this API does not replace the current one. That would actually be a
breaking change but should be done at some point in the future (v15). That is,
`router.navigate` should call this new function. At that point, we can
remove `_lastPathIndex`, `_urlSegment`, and `_correctedPathIndex` from
the `ActivatedRoute`, along with all of the logic associated with
determining what those should be. In addition, this would unblock a fix
for #26081 because the `applyRedirects` and `recognize` operations
could be combined into one.  Overall, this would simplify logic in the router
and reduce code size. It also exposes core routing capabilities as a helper function
which were previously private API, which is a necessary step towards #42953.

As a stress test for this new function, it _was_ swapped in as the
default for `UrlTree` creation in #45859 and tested internally. The
results indicate that this function behaves correctly.

resolves #42191 (Tested directly)
resolves #38276 (The test with a guard covers this case)
resolves #22763 (Tested directly)

PR Close #45877
2022-05-24 10:40:24 -07:00
Andrew Scott e92799c97e test(router): Add tests for initialNavigation: enabledBlocking (#45733)
Adds additional tests to verify `enabledBlocking` functionality. The
initial attempt to fix #44355 would have broken the scenario where a new
navigation cancels the initial navigation. We also cannot rely on
`NavigationError` like the example workaround in that issue report is
doing because there won't be one if a guard simply rejects
the initial nav (#16211).

PR Close #45733
2022-05-18 08:57:30 -07:00
Andrew Scott 4d2e006372 refactor(router): Only create the Route injector when the path matches (#45990)
Currently, the `Router` will create the `EnvironmentInjector` for a
`Route` with `providers` as soon as it _attempts_ to match segments to
the `Route`. Instead, this change updates the logic to only create the
injector once we have confirmed that the `Route` matches. Note that this
will include partial matches where the final navigation still fails with
a "cannot match any routes to segment" error. We need to maintain the
injector hierarchy so we still need to create parent injectors before
descending into the child routes and determining if there is a full
match or just a partial one.

resolves #45988

PR Close #45990
2022-05-13 12:19:16 -07:00
Andrew Scott d4fc12fa19 fix(router): Remove deprecated initialNavigation option (#45729)
BREAKING CHANGE:
`initialNavigation: 'enabled'` was deprecated in v11 and is replaced by
`initialNavigation: 'enabledBlocking'`.

PR Close #45729
2022-04-28 14:40:03 -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 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 6c4d9ebd3a test(common): Fix flaky Location test (#45683)
This test has proven to be flaky. This commit greatly simplifies the
test and moves it to a more appropriate location (pun intended).

PR Close #45683
2022-04-19 20:17:56 -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 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
Kristiyan Kostadinov 41223a81f2 build: update to jasmine 4.0 (#45558)
Updates us to version 4.0 of Jasmine and fixes some errors that were the result of us depending upon deprecated APIs. We need to do this both to stay up to date and because it was going to break eventually, because one of the Bazel packages was logging a deprecation warning that version 4.0 was required.

There were also some cases where the state of `ngDevMode` had started leaking out between tests.

PR Close #45558
2022-04-11 16:25:28 +00:00
Jessica Janiuk 7a37fe9f28 Revert "build: update to jasmine 4.0 (#45558)" (#45566)
This reverts commit a248df0682.

PR Close #45566
2022-04-08 19:07:29 +00:00
Kristiyan Kostadinov a248df0682 build: update to jasmine 4.0 (#45558)
Updates us to version 4.0 of Jasmine and fixes some errors that were the result of us depending upon deprecated APIs. We need to do this both to stay up to date and because it was going to break eventually, because one of the Bazel packages was logging a deprecation warning that version 4.0 was required.

There were also some cases where the state of `ngDevMode` had started leaking out between tests.

PR Close #45558
2022-04-08 15:55:58 +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 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 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
arturovt f58ad88504 test(common): remove initial navigation since it may redirect to debug.html (#45171)
The `should unregister a URL change listener` may fail in Firefox randomly because of
the `initialNavigation` being set to `true`. This may navigate to `/debug.html` and the
router throws an error `Cannot match any routes: 'debug.html'`.

PR Close #45171
2022-02-23 09:42:44 -08:00