@angular/router 12.0.1 → 12.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/router-testing.umd.js +1 -1
- package/bundles/router-upgrade.umd.js +1 -1
- package/bundles/router.umd.js +124 -28
- package/bundles/router.umd.js.map +1 -1
- package/esm2015/src/apply_redirects.js +3 -2
- package/esm2015/src/config.js +1 -1
- package/esm2015/src/events.js +2 -2
- package/esm2015/src/router.js +106 -22
- package/esm2015/src/router_config_loader.js +7 -2
- package/esm2015/src/router_state.js +5 -1
- package/esm2015/src/url_tree.js +5 -3
- package/esm2015/src/version.js +1 -1
- package/fesm2015/router.js +124 -28
- package/fesm2015/router.js.map +1 -1
- package/fesm2015/testing.js +1 -1
- package/fesm2015/upgrade.js +1 -1
- package/package.json +5 -5
- package/router.d.ts +45 -7
- package/router.metadata.json +1 -1
- package/testing/testing.d.ts +1 -1
- package/testing.d.ts +1 -1
- package/upgrade/upgrade.d.ts +1 -1
- package/upgrade.d.ts +1 -1
package/fesm2015/router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v12.0.
|
|
2
|
+
* @license Angular v12.0.5
|
|
3
3
|
* (c) 2010-2021 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -99,7 +99,7 @@ class NavigationEnd extends RouterEvent {
|
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
101
|
* An event triggered when a navigation is canceled, directly or indirectly.
|
|
102
|
-
* This can happen when a route guard
|
|
102
|
+
* This can happen for several reasons including when a route guard
|
|
103
103
|
* returns `false` or initiates a redirect by returning a `UrlTree`.
|
|
104
104
|
*
|
|
105
105
|
* @see `NavigationStart`
|
|
@@ -969,12 +969,14 @@ function serializeMatrixParams(params) {
|
|
|
969
969
|
.join('');
|
|
970
970
|
}
|
|
971
971
|
function serializeQueryParams(params) {
|
|
972
|
-
const strParams = Object.keys(params)
|
|
972
|
+
const strParams = Object.keys(params)
|
|
973
|
+
.map((name) => {
|
|
973
974
|
const value = params[name];
|
|
974
975
|
return Array.isArray(value) ?
|
|
975
976
|
value.map(v => `${encodeUriQuery(name)}=${encodeUriQuery(v)}`).join('&') :
|
|
976
977
|
`${encodeUriQuery(name)}=${encodeUriQuery(value)}`;
|
|
977
|
-
})
|
|
978
|
+
})
|
|
979
|
+
.filter(s => !!s);
|
|
978
980
|
return strParams.length ? `?${strParams.join('&')}` : '';
|
|
979
981
|
}
|
|
980
982
|
const SEGMENT_RE = /^[^\/()?;=#]+/;
|
|
@@ -1328,6 +1330,10 @@ function createEmptyStateSnapshot(urlTree, rootComponent) {
|
|
|
1328
1330
|
* The following example shows how to construct a component using information from a
|
|
1329
1331
|
* currently activated route.
|
|
1330
1332
|
*
|
|
1333
|
+
* Note: the observables in this class only emit when the current and previous values differ based
|
|
1334
|
+
* on shallow equality. For example, changing deeply nested properties in resolved `data` will not
|
|
1335
|
+
* cause the `ActivatedRoute.data` `Observable` to emit a new value.
|
|
1336
|
+
*
|
|
1331
1337
|
* {@example router/activated-route/module.ts region="activated-route"
|
|
1332
1338
|
* header="activated-route.component.ts"}
|
|
1333
1339
|
*
|
|
@@ -2615,7 +2621,8 @@ class ApplyRedirects {
|
|
|
2615
2621
|
}));
|
|
2616
2622
|
return urlTrees$.pipe(catchError((e) => {
|
|
2617
2623
|
if (e instanceof AbsoluteRedirect) {
|
|
2618
|
-
//
|
|
2624
|
+
// After an absolute redirect we do not apply any more redirects!
|
|
2625
|
+
// If this implementation changes, update the documentation note in `redirectTo`.
|
|
2619
2626
|
this.allowRedirects = false;
|
|
2620
2627
|
// we need to run matching, so we can fetch all lazy-loaded modules
|
|
2621
2628
|
return this.match(e.urlTree);
|
|
@@ -3633,7 +3640,12 @@ class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
|
|
|
3633
3640
|
*/
|
|
3634
3641
|
/**
|
|
3635
3642
|
* The [DI token](guide/glossary/#di-token) for a router configuration.
|
|
3636
|
-
*
|
|
3643
|
+
*
|
|
3644
|
+
* `ROUTES` is a low level API for router configuration via dependency injection.
|
|
3645
|
+
*
|
|
3646
|
+
* We recommend that in almost all cases to use higher level APIs such as `RouterModule.forRoot()`,
|
|
3647
|
+
* `RouterModule.forChild()`, `provideRoutes`, or `Router.resetConfig()`.
|
|
3648
|
+
*
|
|
3637
3649
|
* @publicApi
|
|
3638
3650
|
*/
|
|
3639
3651
|
const ROUTES = new InjectionToken('ROUTES');
|
|
@@ -3864,6 +3876,11 @@ class Router {
|
|
|
3864
3876
|
*/
|
|
3865
3877
|
this.lastLocationChangeInfo = null;
|
|
3866
3878
|
this.navigationId = 0;
|
|
3879
|
+
/**
|
|
3880
|
+
* The id of the currently active page in the router.
|
|
3881
|
+
* Updated to the transition's target id on a successful navigation.
|
|
3882
|
+
*/
|
|
3883
|
+
this.currentPageId = 0;
|
|
3867
3884
|
this.isNgZoneEnabled = false;
|
|
3868
3885
|
/**
|
|
3869
3886
|
* An event stream for routing events in this NgModule.
|
|
@@ -3905,8 +3922,16 @@ class Router {
|
|
|
3905
3922
|
this.routeReuseStrategy = new DefaultRouteReuseStrategy();
|
|
3906
3923
|
/**
|
|
3907
3924
|
* How to handle a navigation request to the current URL. One of:
|
|
3925
|
+
*
|
|
3908
3926
|
* - `'ignore'` : The router ignores the request.
|
|
3909
3927
|
* - `'reload'` : The router reloads the URL. Use to implement a "refresh" feature.
|
|
3928
|
+
*
|
|
3929
|
+
* Note that this only configures whether the Route reprocesses the URL and triggers related
|
|
3930
|
+
* action and events like redirects, guards, and resolvers. By default, the router re-uses a
|
|
3931
|
+
* component instance when it re-navigates to the same component type without visiting a different
|
|
3932
|
+
* component first. This behavior is configured by the `RouteReuseStrategy`. In order to reload
|
|
3933
|
+
* routed components on same url navigation, you need to set `onSameUrlNavigation` to `'reload'`
|
|
3934
|
+
* _and_ provide a `RouteReuseStrategy` which returns `false` for `shouldReuseRoute`.
|
|
3910
3935
|
*/
|
|
3911
3936
|
this.onSameUrlNavigation = 'ignore';
|
|
3912
3937
|
/**
|
|
@@ -3932,6 +3957,24 @@ class Router {
|
|
|
3932
3957
|
* @see `RouterModule`
|
|
3933
3958
|
*/
|
|
3934
3959
|
this.relativeLinkResolution = 'corrected';
|
|
3960
|
+
/**
|
|
3961
|
+
* Configures how the Router attempts to restore state when a navigation is cancelled.
|
|
3962
|
+
*
|
|
3963
|
+
* 'replace' - Always uses `location.replaceState` to set the browser state to the state of the
|
|
3964
|
+
* router before the navigation started.
|
|
3965
|
+
*
|
|
3966
|
+
* 'computed' - Will always return to the same state that corresponds to the actual Angular route
|
|
3967
|
+
* when the navigation gets cancelled right after triggering a `popstate` event.
|
|
3968
|
+
*
|
|
3969
|
+
* The default value is `replace`
|
|
3970
|
+
*
|
|
3971
|
+
* @internal
|
|
3972
|
+
*/
|
|
3973
|
+
// TODO(atscott): Determine how/when/if to make this public API
|
|
3974
|
+
// This shouldn’t be an option at all but may need to be in order to allow migration without a
|
|
3975
|
+
// breaking change. We need to determine if it should be made into public api (or if we forgo
|
|
3976
|
+
// the option and release as a breaking change bug fix in a major version).
|
|
3977
|
+
this.canceledNavigationResolution = 'replace';
|
|
3935
3978
|
const onLoadStart = (r) => this.triggerEvent(new RouteConfigLoadStart(r));
|
|
3936
3979
|
const onLoadEnd = (r) => this.triggerEvent(new RouteConfigLoadEnd(r));
|
|
3937
3980
|
this.ngModule = injector.get(NgModuleRef);
|
|
@@ -3946,6 +3989,7 @@ class Router {
|
|
|
3946
3989
|
this.routerState = createEmptyState(this.currentUrlTree, this.rootComponentType);
|
|
3947
3990
|
this.transitions = new BehaviorSubject({
|
|
3948
3991
|
id: 0,
|
|
3992
|
+
targetPageId: 0,
|
|
3949
3993
|
currentUrlTree: this.currentUrlTree,
|
|
3950
3994
|
currentRawUrl: this.currentUrlTree,
|
|
3951
3995
|
extractedUrl: this.urlHandlingStrategy.extract(this.currentUrlTree),
|
|
@@ -4018,7 +4062,7 @@ class Router {
|
|
|
4018
4062
|
tap(t => {
|
|
4019
4063
|
if (this.urlUpdateStrategy === 'eager') {
|
|
4020
4064
|
if (!t.extras.skipLocationChange) {
|
|
4021
|
-
this.setBrowserUrl(t.urlAfterRedirects,
|
|
4065
|
+
this.setBrowserUrl(t.urlAfterRedirects, t);
|
|
4022
4066
|
}
|
|
4023
4067
|
this.browserUrlTree = t.urlAfterRedirects;
|
|
4024
4068
|
}
|
|
@@ -4078,10 +4122,7 @@ class Router {
|
|
|
4078
4122
|
this.triggerEvent(guardsEnd);
|
|
4079
4123
|
}), filter(t => {
|
|
4080
4124
|
if (!t.guardsResult) {
|
|
4081
|
-
this.
|
|
4082
|
-
const navCancel = new NavigationCancel(t.id, this.serializeUrl(t.extractedUrl), '');
|
|
4083
|
-
eventsSubject.next(navCancel);
|
|
4084
|
-
t.resolve(false);
|
|
4125
|
+
this.cancelNavigationTransition(t, '');
|
|
4085
4126
|
return false;
|
|
4086
4127
|
}
|
|
4087
4128
|
return true;
|
|
@@ -4098,9 +4139,7 @@ class Router {
|
|
|
4098
4139
|
next: () => dataResolved = true,
|
|
4099
4140
|
complete: () => {
|
|
4100
4141
|
if (!dataResolved) {
|
|
4101
|
-
|
|
4102
|
-
eventsSubject.next(navCancel);
|
|
4103
|
-
t.resolve(false);
|
|
4142
|
+
this.cancelNavigationTransition(t, `At least one route resolver didn't emit any value.`);
|
|
4104
4143
|
}
|
|
4105
4144
|
}
|
|
4106
4145
|
}));
|
|
@@ -4137,7 +4176,7 @@ class Router {
|
|
|
4137
4176
|
this.routerState = t.targetRouterState;
|
|
4138
4177
|
if (this.urlUpdateStrategy === 'deferred') {
|
|
4139
4178
|
if (!t.extras.skipLocationChange) {
|
|
4140
|
-
this.setBrowserUrl(this.rawUrlTree,
|
|
4179
|
+
this.setBrowserUrl(this.rawUrlTree, t);
|
|
4141
4180
|
}
|
|
4142
4181
|
this.browserUrlTree = t.urlAfterRedirects;
|
|
4143
4182
|
}
|
|
@@ -4164,10 +4203,7 @@ class Router {
|
|
|
4164
4203
|
// sync code which looks for a value here in order to determine whether or
|
|
4165
4204
|
// not to handle a given popstate event or to leave it to the Angular
|
|
4166
4205
|
// router.
|
|
4167
|
-
this.
|
|
4168
|
-
const navCancel = new NavigationCancel(t.id, this.serializeUrl(t.extractedUrl), `Navigation ID ${t.id} is not equal to the current navigation id ${this.navigationId}`);
|
|
4169
|
-
eventsSubject.next(navCancel);
|
|
4170
|
-
t.resolve(false);
|
|
4206
|
+
this.cancelNavigationTransition(t, `Navigation ID ${t.id} is not equal to the current navigation id ${this.navigationId}`);
|
|
4171
4207
|
}
|
|
4172
4208
|
// currentNavigation should always be reset to null here. If navigation was
|
|
4173
4209
|
// successful, lastSuccessfulTransition will have already been set. Therefore
|
|
@@ -4279,6 +4315,7 @@ class Router {
|
|
|
4279
4315
|
if (state) {
|
|
4280
4316
|
const stateCopy = Object.assign({}, state);
|
|
4281
4317
|
delete stateCopy.navigationId;
|
|
4318
|
+
delete stateCopy.ɵrouterPageId;
|
|
4282
4319
|
if (Object.keys(stateCopy).length !== 0) {
|
|
4283
4320
|
extras.state = stateCopy;
|
|
4284
4321
|
}
|
|
@@ -4473,7 +4510,14 @@ class Router {
|
|
|
4473
4510
|
}
|
|
4474
4511
|
const urlTree = isUrlTree(url) ? url : this.parseUrl(url);
|
|
4475
4512
|
const mergedTree = this.urlHandlingStrategy.merge(urlTree, this.rawUrlTree);
|
|
4476
|
-
|
|
4513
|
+
let restoredState = null;
|
|
4514
|
+
if (this.canceledNavigationResolution === 'computed') {
|
|
4515
|
+
const isInitialPage = this.currentPageId === 0;
|
|
4516
|
+
if (isInitialPage || extras.skipLocationChange || extras.replaceUrl) {
|
|
4517
|
+
restoredState = this.location.getState();
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4520
|
+
return this.scheduleNavigation(mergedTree, 'imperative', restoredState, extras);
|
|
4477
4521
|
}
|
|
4478
4522
|
/**
|
|
4479
4523
|
* Navigate based on the provided array of commands and a starting point.
|
|
@@ -4554,6 +4598,7 @@ class Router {
|
|
|
4554
4598
|
this.navigations.subscribe(t => {
|
|
4555
4599
|
this.navigated = true;
|
|
4556
4600
|
this.lastSuccessfulId = t.id;
|
|
4601
|
+
this.currentPageId = t.targetPageId;
|
|
4557
4602
|
this.events
|
|
4558
4603
|
.next(new NavigationEnd(t.id, this.serializeUrl(t.extractedUrl), this.serializeUrl(this.currentUrlTree)));
|
|
4559
4604
|
this.lastSuccessfulNavigation = this.currentNavigation;
|
|
@@ -4604,8 +4649,24 @@ class Router {
|
|
|
4604
4649
|
});
|
|
4605
4650
|
}
|
|
4606
4651
|
const id = ++this.navigationId;
|
|
4652
|
+
let targetPageId;
|
|
4653
|
+
if (this.canceledNavigationResolution === 'computed') {
|
|
4654
|
+
// If the `ɵrouterPageId` exist in the state then `targetpageId` should have the value of
|
|
4655
|
+
// `ɵrouterPageId`
|
|
4656
|
+
if (restoredState && restoredState.ɵrouterPageId) {
|
|
4657
|
+
targetPageId = restoredState.ɵrouterPageId;
|
|
4658
|
+
}
|
|
4659
|
+
else {
|
|
4660
|
+
targetPageId = this.currentPageId + 1;
|
|
4661
|
+
}
|
|
4662
|
+
}
|
|
4663
|
+
else {
|
|
4664
|
+
// This is unused when `canceledNavigationResolution` is not computed.
|
|
4665
|
+
targetPageId = 0;
|
|
4666
|
+
}
|
|
4607
4667
|
this.setTransition({
|
|
4608
4668
|
id,
|
|
4669
|
+
targetPageId,
|
|
4609
4670
|
source,
|
|
4610
4671
|
restoredState,
|
|
4611
4672
|
currentUrlTree: this.currentUrlTree,
|
|
@@ -4624,15 +4685,14 @@ class Router {
|
|
|
4624
4685
|
return Promise.reject(e);
|
|
4625
4686
|
});
|
|
4626
4687
|
}
|
|
4627
|
-
setBrowserUrl(url,
|
|
4688
|
+
setBrowserUrl(url, t) {
|
|
4628
4689
|
const path = this.urlSerializer.serialize(url);
|
|
4629
|
-
state = state
|
|
4630
|
-
if (this.location.isCurrentPathEqualTo(path) || replaceUrl) {
|
|
4631
|
-
|
|
4632
|
-
this.location.replaceState(path, '', Object.assign(Object.assign({}, state), { navigationId: id }));
|
|
4690
|
+
const state = Object.assign(Object.assign({}, t.extras.state), this.generateNgRouterState(t.id, t.targetPageId));
|
|
4691
|
+
if (this.location.isCurrentPathEqualTo(path) || !!t.extras.replaceUrl) {
|
|
4692
|
+
this.location.replaceState(path, '', state);
|
|
4633
4693
|
}
|
|
4634
4694
|
else {
|
|
4635
|
-
this.location.go(path, '',
|
|
4695
|
+
this.location.go(path, '', state);
|
|
4636
4696
|
}
|
|
4637
4697
|
}
|
|
4638
4698
|
resetStateAndUrl(storedState, storedUrl, rawUrl) {
|
|
@@ -4642,7 +4702,43 @@ class Router {
|
|
|
4642
4702
|
this.resetUrlToCurrentUrlTree();
|
|
4643
4703
|
}
|
|
4644
4704
|
resetUrlToCurrentUrlTree() {
|
|
4645
|
-
this.location.replaceState(this.urlSerializer.serialize(this.rawUrlTree), '',
|
|
4705
|
+
this.location.replaceState(this.urlSerializer.serialize(this.rawUrlTree), '', this.generateNgRouterState(this.lastSuccessfulId, this.currentPageId));
|
|
4706
|
+
}
|
|
4707
|
+
/**
|
|
4708
|
+
* Responsible for handling the cancellation of a navigation:
|
|
4709
|
+
* - performs the necessary rollback action to restore the browser URL to the
|
|
4710
|
+
* state before the transition
|
|
4711
|
+
* - triggers the `NavigationCancel` event
|
|
4712
|
+
* - resolves the transition promise with `false`
|
|
4713
|
+
*/
|
|
4714
|
+
cancelNavigationTransition(t, reason) {
|
|
4715
|
+
if (this.canceledNavigationResolution === 'computed') {
|
|
4716
|
+
// The navigator change the location before triggered the browser event,
|
|
4717
|
+
// so we need to go back to the current url if the navigation is canceled.
|
|
4718
|
+
// Also, when navigation gets cancelled while using url update strategy eager, then we need to
|
|
4719
|
+
// go back. Because, when `urlUpdateSrategy` is `eager`; `setBrowserUrl` method is called
|
|
4720
|
+
// before any verification.
|
|
4721
|
+
if (t.source === 'popstate' || this.urlUpdateStrategy === 'eager') {
|
|
4722
|
+
const targetPagePosition = this.currentPageId - t.targetPageId;
|
|
4723
|
+
this.location.historyGo(targetPagePosition);
|
|
4724
|
+
}
|
|
4725
|
+
else {
|
|
4726
|
+
// If update is not 'eager' and the transition navigation source isn't 'popstate', then the
|
|
4727
|
+
// navigation was cancelled before any browser url change so nothing needs to be restored.
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
else {
|
|
4731
|
+
this.resetUrlToCurrentUrlTree();
|
|
4732
|
+
}
|
|
4733
|
+
const navCancel = new NavigationCancel(t.id, this.serializeUrl(t.extractedUrl), reason);
|
|
4734
|
+
this.triggerEvent(navCancel);
|
|
4735
|
+
t.resolve(false);
|
|
4736
|
+
}
|
|
4737
|
+
generateNgRouterState(navigationId, routerPageId) {
|
|
4738
|
+
if (this.canceledNavigationResolution === 'computed') {
|
|
4739
|
+
return { navigationId, ɵrouterPageId: routerPageId };
|
|
4740
|
+
}
|
|
4741
|
+
return { navigationId };
|
|
4646
4742
|
}
|
|
4647
4743
|
}
|
|
4648
4744
|
Router.decorators = [
|
|
@@ -5883,7 +5979,7 @@ function provideRouterInitializer() {
|
|
|
5883
5979
|
/**
|
|
5884
5980
|
* @publicApi
|
|
5885
5981
|
*/
|
|
5886
|
-
const VERSION = new Version('12.0.
|
|
5982
|
+
const VERSION = new Version('12.0.5');
|
|
5887
5983
|
|
|
5888
5984
|
/**
|
|
5889
5985
|
* @license
|