@angular/router 14.0.0-next.11 → 14.0.0-next.14

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.
Files changed (37) hide show
  1. package/esm2020/src/apply_redirects.mjs +56 -46
  2. package/esm2020/src/components/empty_outlet.mjs +3 -3
  3. package/esm2020/src/create_url_tree.mjs +25 -11
  4. package/esm2020/src/directives/router_link.mjs +6 -6
  5. package/esm2020/src/directives/router_link_active.mjs +3 -3
  6. package/esm2020/src/directives/router_outlet.mjs +24 -15
  7. package/esm2020/src/models.mjs +2 -7
  8. package/esm2020/src/operators/activate_routes.mjs +7 -14
  9. package/esm2020/src/operators/apply_redirects.mjs +3 -3
  10. package/esm2020/src/operators/resolve_data.mjs +5 -12
  11. package/esm2020/src/page_title_strategy.mjs +3 -3
  12. package/esm2020/src/recognize.mjs +24 -6
  13. package/esm2020/src/router.mjs +9 -6
  14. package/esm2020/src/router_config_loader.mjs +29 -18
  15. package/esm2020/src/router_module.mjs +10 -9
  16. package/esm2020/src/router_outlet_context.mjs +6 -1
  17. package/esm2020/src/router_preloader.mjs +31 -24
  18. package/esm2020/src/router_scroller.mjs +3 -3
  19. package/esm2020/src/router_state.mjs +3 -3
  20. package/esm2020/src/url_tree.mjs +1 -1
  21. package/esm2020/src/utils/config.mjs +44 -1
  22. package/esm2020/src/utils/config_matching.mjs +4 -1
  23. package/esm2020/src/utils/preactivation.mjs +5 -14
  24. package/esm2020/src/version.mjs +1 -1
  25. package/esm2020/testing/src/router_testing_module.mjs +4 -4
  26. package/fesm2015/router.mjs +719 -625
  27. package/fesm2015/router.mjs.map +1 -1
  28. package/fesm2015/testing.mjs +5 -5
  29. package/fesm2015/upgrade.mjs +1 -1
  30. package/fesm2020/router.mjs +709 -625
  31. package/fesm2020/router.mjs.map +1 -1
  32. package/fesm2020/testing.mjs +5 -5
  33. package/fesm2020/upgrade.mjs +1 -1
  34. package/package.json +4 -4
  35. package/router.d.ts +54 -14
  36. package/testing/testing.d.ts +1 -1
  37. package/upgrade/upgrade.d.ts +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v14.0.0-next.11
2
+ * @license Angular v14.0.0-next.14
3
3
  * (c) 2010-2022 Google LLC. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -7,9 +7,9 @@
7
7
  import * as i3 from '@angular/common';
8
8
  import { Location, LocationStrategy, PlatformLocation, APP_BASE_HREF, ViewportScroller, HashLocationStrategy, PathLocationStrategy, LOCATION_INITIALIZED } from '@angular/common';
9
9
  import * as i0 from '@angular/core';
10
- import { ɵisObservable, ɵisPromise, EventEmitter, Directive, Attribute, Output, Component, NgModuleRef, InjectionToken, InjectFlags, NgModuleFactory, ɵConsole, NgZone, Injectable, ɵcoerceToBoolean, Input, HostListener, HostBinding, Optional, ContentChildren, Injector, Compiler, NgProbeToken, ANALYZE_FOR_ENTRY_COMPONENTS, SkipSelf, Inject, APP_INITIALIZER, APP_BOOTSTRAP_LISTENER, NgModule, ApplicationRef, Version } from '@angular/core';
10
+ import { ɵisObservable, ɵisPromise, EventEmitter, Directive, Attribute, Output, Component, ComponentFactoryResolver, createEnvironmentInjector, InjectionToken, InjectFlags, NgModuleFactory, Injectable, NgModuleRef, ɵConsole, NgZone, ɵcoerceToBoolean, Input, HostListener, HostBinding, Optional, ContentChildren, Injector, Compiler, NgProbeToken, ANALYZE_FOR_ENTRY_COMPONENTS, SkipSelf, Inject, APP_INITIALIZER, APP_BOOTSTRAP_LISTENER, NgModule, ApplicationRef, Version } from '@angular/core';
11
11
  import { from, of, BehaviorSubject, combineLatest, throwError, EmptyError, concat, defer, Observable, EMPTY, ConnectableObservable, Subject } from 'rxjs';
12
- import { map, switchMap, take, startWith, scan, filter, catchError, concatMap, last as last$1, first, mergeMap, tap, takeLast, refCount, finalize, mergeAll } from 'rxjs/operators';
12
+ import { map, switchMap, take, startWith, scan, filter, catchError, concatMap, last as last$1, first, mergeMap, tap, takeLast, mapTo, finalize, refCount, mergeAll } from 'rxjs/operators';
13
13
  import * as i1 from '@angular/platform-browser';
14
14
 
15
15
  /**
@@ -1362,7 +1362,6 @@ class ActivatedRoute {
1362
1362
  /** The outlet name of the route, a constant. */
1363
1363
  outlet,
1364
1364
  /** The component of the route, a constant. */
1365
- // TODO(vsavkin): remove |string
1366
1365
  component, futureSnapshot) {
1367
1366
  this.url = url;
1368
1367
  this.params = params;
@@ -1517,7 +1516,7 @@ class ActivatedRouteSnapshot {
1517
1516
  /** The outlet name of the route */
1518
1517
  outlet,
1519
1518
  /** The component of the route */
1520
- component, routeConfig, urlSegment, lastPathIndex, resolve) {
1519
+ component, routeConfig, urlSegment, lastPathIndex, resolve, correctedLastPathIndex) {
1521
1520
  this.url = url;
1522
1521
  this.params = params;
1523
1522
  this.queryParams = queryParams;
@@ -1528,6 +1527,7 @@ class ActivatedRouteSnapshot {
1528
1527
  this.routeConfig = routeConfig;
1529
1528
  this._urlSegment = urlSegment;
1530
1529
  this._lastPathIndex = lastPathIndex;
1530
+ this._correctedLastPathIndex = correctedLastPathIndex ?? lastPathIndex;
1531
1531
  this._resolve = resolve;
1532
1532
  }
1533
1533
  /** The root of the router state */
@@ -1719,11 +1719,26 @@ function createUrlTree(route, urlTree, commands, queryParams, fragment) {
1719
1719
  if (nav.toRoot()) {
1720
1720
  return tree(urlTree.root, urlTree.root, new UrlSegmentGroup([], {}), queryParams, fragment);
1721
1721
  }
1722
- const startingPosition = findStartingPosition(nav, urlTree, route);
1723
- const segmentGroup = startingPosition.processChildren ?
1724
- updateSegmentGroupChildren(startingPosition.segmentGroup, startingPosition.index, nav.commands) :
1725
- updateSegmentGroup(startingPosition.segmentGroup, startingPosition.index, nav.commands);
1726
- return tree(urlTree.root, startingPosition.segmentGroup, segmentGroup, queryParams, fragment);
1722
+ function createTreeUsingPathIndex(lastPathIndex) {
1723
+ const startingPosition = findStartingPosition(nav, urlTree, route.snapshot?._urlSegment, lastPathIndex);
1724
+ const segmentGroup = startingPosition.processChildren ?
1725
+ updateSegmentGroupChildren(startingPosition.segmentGroup, startingPosition.index, nav.commands) :
1726
+ updateSegmentGroup(startingPosition.segmentGroup, startingPosition.index, nav.commands);
1727
+ return tree(urlTree.root, startingPosition.segmentGroup, segmentGroup, queryParams, fragment);
1728
+ }
1729
+ // Note: The types should disallow `snapshot` from being `undefined` but due to test mocks, this
1730
+ // may be the case. Since we try to access it at an earlier point before the refactor to add the
1731
+ // warning for `relativeLinkResolution: 'legacy'`, this may cause failures in tests where it
1732
+ // didn't before.
1733
+ const result = createTreeUsingPathIndex(route.snapshot?._lastPathIndex);
1734
+ // Check if application is relying on `relativeLinkResolution: 'legacy'`
1735
+ if (typeof ngDevMode === 'undefined' || !!ngDevMode) {
1736
+ const correctedResult = createTreeUsingPathIndex(route.snapshot?._correctedLastPathIndex);
1737
+ if (correctedResult.toString() !== result.toString()) {
1738
+ console.warn(`relativeLinkResolution: 'legacy' is deprecated and will be removed in a future version of Angular. The link to ${result.toString()} will change to ${correctedResult.toString()} if the code is not updated before then.`);
1739
+ }
1740
+ }
1741
+ return result;
1727
1742
  }
1728
1743
  function isMatrixParams(command) {
1729
1744
  return typeof command === 'object' && command != null && !command.outlets && !command.segmentPath;
@@ -1828,12 +1843,11 @@ class Position {
1828
1843
  this.index = index;
1829
1844
  }
1830
1845
  }
1831
- function findStartingPosition(nav, tree, route) {
1846
+ function findStartingPosition(nav, tree, segmentGroup, lastPathIndex) {
1832
1847
  if (nav.isAbsolute) {
1833
1848
  return new Position(tree.root, true, 0);
1834
1849
  }
1835
- if (route.snapshot._lastPathIndex === -1) {
1836
- const segmentGroup = route.snapshot._urlSegment;
1850
+ if (lastPathIndex === -1) {
1837
1851
  // Pathless ActivatedRoute has _lastPathIndex === -1 but should not process children
1838
1852
  // see issue #26224, #13011, #35687
1839
1853
  // However, if the ActivatedRoute is the root we should process children like above.
@@ -1841,8 +1855,8 @@ function findStartingPosition(nav, tree, route) {
1841
1855
  return new Position(segmentGroup, processChildren, 0);
1842
1856
  }
1843
1857
  const modifier = isMatrixParams(nav.commands[0]) ? 0 : 1;
1844
- const index = route.snapshot._lastPathIndex + modifier;
1845
- return createPositionApplyingDoubleDots(route.snapshot._urlSegment, index, nav.numberOfDoubleDots);
1858
+ const index = lastPathIndex + modifier;
1859
+ return createPositionApplyingDoubleDots(segmentGroup, index, nav.numberOfDoubleDots);
1846
1860
  }
1847
1861
  function createPositionApplyingDoubleDots(group, index, numberOfDoubleDots) {
1848
1862
  let g = group;
@@ -2005,181 +2019,76 @@ function compare(path, params, segment) {
2005
2019
  * Use of this source code is governed by an MIT-style license that can be
2006
2020
  * found in the LICENSE file at https://angular.io/license
2007
2021
  */
2008
- const activateRoutes = (rootContexts, routeReuseStrategy, forwardEvent) => map(t => {
2009
- new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent)
2010
- .activate(rootContexts);
2011
- return t;
2012
- });
2013
- class ActivateRoutes {
2014
- constructor(routeReuseStrategy, futureState, currState, forwardEvent) {
2015
- this.routeReuseStrategy = routeReuseStrategy;
2016
- this.futureState = futureState;
2017
- this.currState = currState;
2018
- this.forwardEvent = forwardEvent;
2019
- }
2020
- activate(parentContexts) {
2021
- const futureRoot = this.futureState._root;
2022
- const currRoot = this.currState ? this.currState._root : null;
2023
- this.deactivateChildRoutes(futureRoot, currRoot, parentContexts);
2024
- advanceActivatedRoute(this.futureState.root);
2025
- this.activateChildRoutes(futureRoot, currRoot, parentContexts);
2026
- }
2027
- // De-activate the child route that are not re-used for the future state
2028
- deactivateChildRoutes(futureNode, currNode, contexts) {
2029
- const children = nodeChildrenAsMap(currNode);
2030
- // Recurse on the routes active in the future state to de-activate deeper children
2031
- futureNode.children.forEach(futureChild => {
2032
- const childOutletName = futureChild.value.outlet;
2033
- this.deactivateRoutes(futureChild, children[childOutletName], contexts);
2034
- delete children[childOutletName];
2035
- });
2036
- // De-activate the routes that will not be re-used
2037
- forEach(children, (v, childName) => {
2038
- this.deactivateRouteAndItsChildren(v, contexts);
2039
- });
2040
- }
2041
- deactivateRoutes(futureNode, currNode, parentContext) {
2042
- const future = futureNode.value;
2043
- const curr = currNode ? currNode.value : null;
2044
- if (future === curr) {
2045
- // Reusing the node, check to see if the children need to be de-activated
2046
- if (future.component) {
2047
- // If we have a normal route, we need to go through an outlet.
2048
- const context = parentContext.getContext(future.outlet);
2049
- if (context) {
2050
- this.deactivateChildRoutes(futureNode, currNode, context.children);
2051
- }
2052
- }
2053
- else {
2054
- // if we have a componentless route, we recurse but keep the same outlet map.
2055
- this.deactivateChildRoutes(futureNode, currNode, parentContext);
2056
- }
2057
- }
2058
- else {
2059
- if (curr) {
2060
- // Deactivate the current route which will not be re-used
2061
- this.deactivateRouteAndItsChildren(currNode, parentContext);
2062
- }
2063
- }
2022
+ /**
2023
+ * Store contextual information about a `RouterOutlet`
2024
+ *
2025
+ * @publicApi
2026
+ */
2027
+ class OutletContext {
2028
+ constructor() {
2029
+ this.outlet = null;
2030
+ this.route = null;
2031
+ /**
2032
+ * @deprecated Passing a resolver to retrieve a component factory is not required and is
2033
+ * deprecated since v14.
2034
+ */
2035
+ this.resolver = null;
2036
+ this.injector = null;
2037
+ this.children = new ChildrenOutletContexts();
2038
+ this.attachRef = null;
2064
2039
  }
2065
- deactivateRouteAndItsChildren(route, parentContexts) {
2066
- // If there is no component, the Route is never attached to an outlet (because there is no
2067
- // component to attach).
2068
- if (route.value.component && this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {
2069
- this.detachAndStoreRouteSubtree(route, parentContexts);
2070
- }
2071
- else {
2072
- this.deactivateRouteAndOutlet(route, parentContexts);
2073
- }
2040
+ }
2041
+ /**
2042
+ * Store contextual information about the children (= nested) `RouterOutlet`
2043
+ *
2044
+ * @publicApi
2045
+ */
2046
+ class ChildrenOutletContexts {
2047
+ constructor() {
2048
+ // contexts for child outlets, by name.
2049
+ this.contexts = new Map();
2074
2050
  }
2075
- detachAndStoreRouteSubtree(route, parentContexts) {
2076
- const context = parentContexts.getContext(route.value.outlet);
2077
- const contexts = context && route.value.component ? context.children : parentContexts;
2078
- const children = nodeChildrenAsMap(route);
2079
- for (const childOutlet of Object.keys(children)) {
2080
- this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2081
- }
2082
- if (context && context.outlet) {
2083
- const componentRef = context.outlet.detach();
2084
- const contexts = context.children.onOutletDeactivated();
2085
- this.routeReuseStrategy.store(route.value.snapshot, { componentRef, route, contexts });
2086
- }
2051
+ /** Called when a `RouterOutlet` directive is instantiated */
2052
+ onChildOutletCreated(childName, outlet) {
2053
+ const context = this.getOrCreateContext(childName);
2054
+ context.outlet = outlet;
2055
+ this.contexts.set(childName, context);
2087
2056
  }
2088
- deactivateRouteAndOutlet(route, parentContexts) {
2089
- const context = parentContexts.getContext(route.value.outlet);
2090
- // The context could be `null` if we are on a componentless route but there may still be
2091
- // children that need deactivating.
2092
- const contexts = context && route.value.component ? context.children : parentContexts;
2093
- const children = nodeChildrenAsMap(route);
2094
- for (const childOutlet of Object.keys(children)) {
2095
- this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2096
- }
2097
- if (context && context.outlet) {
2098
- // Destroy the component
2099
- context.outlet.deactivate();
2100
- // Destroy the contexts for all the outlets that were in the component
2101
- context.children.onOutletDeactivated();
2102
- // Clear the information about the attached component on the context but keep the reference to
2103
- // the outlet.
2057
+ /**
2058
+ * Called when a `RouterOutlet` directive is destroyed.
2059
+ * We need to keep the context as the outlet could be destroyed inside a NgIf and might be
2060
+ * re-created later.
2061
+ */
2062
+ onChildOutletDestroyed(childName) {
2063
+ const context = this.getContext(childName);
2064
+ if (context) {
2065
+ context.outlet = null;
2104
2066
  context.attachRef = null;
2105
- context.resolver = null;
2106
- context.route = null;
2107
2067
  }
2108
2068
  }
2109
- activateChildRoutes(futureNode, currNode, contexts) {
2110
- const children = nodeChildrenAsMap(currNode);
2111
- futureNode.children.forEach(c => {
2112
- this.activateRoutes(c, children[c.value.outlet], contexts);
2113
- this.forwardEvent(new ActivationEnd(c.value.snapshot));
2114
- });
2115
- if (futureNode.children.length) {
2116
- this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));
2117
- }
2069
+ /**
2070
+ * Called when the corresponding route is deactivated during navigation.
2071
+ * Because the component get destroyed, all children outlet are destroyed.
2072
+ */
2073
+ onOutletDeactivated() {
2074
+ const contexts = this.contexts;
2075
+ this.contexts = new Map();
2076
+ return contexts;
2118
2077
  }
2119
- activateRoutes(futureNode, currNode, parentContexts) {
2120
- const future = futureNode.value;
2121
- const curr = currNode ? currNode.value : null;
2122
- advanceActivatedRoute(future);
2123
- // reusing the node
2124
- if (future === curr) {
2125
- if (future.component) {
2126
- // If we have a normal route, we need to go through an outlet.
2127
- const context = parentContexts.getOrCreateContext(future.outlet);
2128
- this.activateChildRoutes(futureNode, currNode, context.children);
2129
- }
2130
- else {
2131
- // if we have a componentless route, we recurse but keep the same outlet map.
2132
- this.activateChildRoutes(futureNode, currNode, parentContexts);
2133
- }
2134
- }
2135
- else {
2136
- if (future.component) {
2137
- // if we have a normal route, we need to place the component into the outlet and recurse.
2138
- const context = parentContexts.getOrCreateContext(future.outlet);
2139
- if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
2140
- const stored = this.routeReuseStrategy.retrieve(future.snapshot);
2141
- this.routeReuseStrategy.store(future.snapshot, null);
2142
- context.children.onOutletReAttached(stored.contexts);
2143
- context.attachRef = stored.componentRef;
2144
- context.route = stored.route.value;
2145
- if (context.outlet) {
2146
- // Attach right away when the outlet has already been instantiated
2147
- // Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated
2148
- context.outlet.attach(stored.componentRef, stored.route.value);
2149
- }
2150
- advanceActivatedRoute(stored.route.value);
2151
- this.activateChildRoutes(futureNode, null, context.children);
2152
- }
2153
- else {
2154
- const config = parentLoadedConfig(future.snapshot);
2155
- const cmpFactoryResolver = config ? config.module.componentFactoryResolver : null;
2156
- context.attachRef = null;
2157
- context.route = future;
2158
- context.resolver = cmpFactoryResolver;
2159
- if (context.outlet) {
2160
- // Activate the outlet when it has already been instantiated
2161
- // Otherwise it will get activated from its `ngOnInit` when instantiated
2162
- context.outlet.activateWith(future, cmpFactoryResolver);
2163
- }
2164
- this.activateChildRoutes(futureNode, null, context.children);
2165
- }
2166
- }
2167
- else {
2168
- // if we have a componentless route, we recurse but keep the same outlet map.
2169
- this.activateChildRoutes(futureNode, null, parentContexts);
2170
- }
2078
+ onOutletReAttached(contexts) {
2079
+ this.contexts = contexts;
2080
+ }
2081
+ getOrCreateContext(childName) {
2082
+ let context = this.getContext(childName);
2083
+ if (!context) {
2084
+ context = new OutletContext();
2085
+ this.contexts.set(childName, context);
2171
2086
  }
2087
+ return context;
2172
2088
  }
2173
- }
2174
- function parentLoadedConfig(snapshot) {
2175
- for (let s = snapshot.parent; s; s = s.parent) {
2176
- const route = s.routeConfig;
2177
- if (route && route._loadedConfig)
2178
- return route._loadedConfig;
2179
- if (route && route.component)
2180
- return null;
2089
+ getContext(childName) {
2090
+ return this.contexts.get(childName) || null;
2181
2091
  }
2182
- return null;
2183
2092
  }
2184
2093
 
2185
2094
  /**
@@ -2189,182 +2098,13 @@ function parentLoadedConfig(snapshot) {
2189
2098
  * Use of this source code is governed by an MIT-style license that can be
2190
2099
  * found in the LICENSE file at https://angular.io/license
2191
2100
  */
2192
- class LoadedRouterConfig {
2193
- constructor(routes, module) {
2194
- this.routes = routes;
2195
- this.module = module;
2196
- }
2197
- }
2198
-
2199
2101
  /**
2200
- * @license
2201
- * Copyright Google LLC All Rights Reserved.
2102
+ * @description
2202
2103
  *
2203
- * Use of this source code is governed by an MIT-style license that can be
2204
- * found in the LICENSE file at https://angular.io/license
2205
- */
2206
- /**
2207
- * Simple function check, but generic so type inference will flow. Example:
2104
+ * Acts as a placeholder that Angular dynamically fills based on the current router state.
2208
2105
  *
2209
- * function product(a: number, b: number) {
2210
- * return a * b;
2211
- * }
2212
- *
2213
- * if (isFunction<product>(fn)) {
2214
- * return fn(1, 2);
2215
- * } else {
2216
- * throw "Must provide the `product` function";
2217
- * }
2218
- */
2219
- function isFunction(v) {
2220
- return typeof v === 'function';
2221
- }
2222
- function isBoolean(v) {
2223
- return typeof v === 'boolean';
2224
- }
2225
- function isUrlTree(v) {
2226
- return v instanceof UrlTree;
2227
- }
2228
- function isCanLoad(guard) {
2229
- return guard && isFunction(guard.canLoad);
2230
- }
2231
- function isCanActivate(guard) {
2232
- return guard && isFunction(guard.canActivate);
2233
- }
2234
- function isCanActivateChild(guard) {
2235
- return guard && isFunction(guard.canActivateChild);
2236
- }
2237
- function isCanDeactivate(guard) {
2238
- return guard && isFunction(guard.canDeactivate);
2239
- }
2240
-
2241
- /**
2242
- * @license
2243
- * Copyright Google LLC All Rights Reserved.
2244
- *
2245
- * Use of this source code is governed by an MIT-style license that can be
2246
- * found in the LICENSE file at https://angular.io/license
2247
- */
2248
- const INITIAL_VALUE = Symbol('INITIAL_VALUE');
2249
- function prioritizedGuardValue() {
2250
- return switchMap(obs => {
2251
- return combineLatest(obs.map(o => o.pipe(take(1), startWith(INITIAL_VALUE))))
2252
- .pipe(scan((acc, list) => {
2253
- let isPending = false;
2254
- return list.reduce((innerAcc, val, i) => {
2255
- if (innerAcc !== INITIAL_VALUE)
2256
- return innerAcc;
2257
- // Toggle pending flag if any values haven't been set yet
2258
- if (val === INITIAL_VALUE)
2259
- isPending = true;
2260
- // Any other return values are only valid if we haven't yet hit a pending
2261
- // call. This guarantees that in the case of a guard at the bottom of the
2262
- // tree that returns a redirect, we will wait for the higher priority
2263
- // guard at the top to finish before performing the redirect.
2264
- if (!isPending) {
2265
- // Early return when we hit a `false` value as that should always
2266
- // cancel navigation
2267
- if (val === false)
2268
- return val;
2269
- if (i === list.length - 1 || isUrlTree(val)) {
2270
- return val;
2271
- }
2272
- }
2273
- return innerAcc;
2274
- }, acc);
2275
- }, INITIAL_VALUE), filter(item => item !== INITIAL_VALUE), map(item => isUrlTree(item) ? item : item === true), //
2276
- take(1));
2277
- });
2278
- }
2279
-
2280
- /**
2281
- * @license
2282
- * Copyright Google LLC All Rights Reserved.
2283
- *
2284
- * Use of this source code is governed by an MIT-style license that can be
2285
- * found in the LICENSE file at https://angular.io/license
2286
- */
2287
- /**
2288
- * Store contextual information about a `RouterOutlet`
2289
- *
2290
- * @publicApi
2291
- */
2292
- class OutletContext {
2293
- constructor() {
2294
- this.outlet = null;
2295
- this.route = null;
2296
- this.resolver = null;
2297
- this.children = new ChildrenOutletContexts();
2298
- this.attachRef = null;
2299
- }
2300
- }
2301
- /**
2302
- * Store contextual information about the children (= nested) `RouterOutlet`
2303
- *
2304
- * @publicApi
2305
- */
2306
- class ChildrenOutletContexts {
2307
- constructor() {
2308
- // contexts for child outlets, by name.
2309
- this.contexts = new Map();
2310
- }
2311
- /** Called when a `RouterOutlet` directive is instantiated */
2312
- onChildOutletCreated(childName, outlet) {
2313
- const context = this.getOrCreateContext(childName);
2314
- context.outlet = outlet;
2315
- this.contexts.set(childName, context);
2316
- }
2317
- /**
2318
- * Called when a `RouterOutlet` directive is destroyed.
2319
- * We need to keep the context as the outlet could be destroyed inside a NgIf and might be
2320
- * re-created later.
2321
- */
2322
- onChildOutletDestroyed(childName) {
2323
- const context = this.getContext(childName);
2324
- if (context) {
2325
- context.outlet = null;
2326
- context.attachRef = null;
2327
- }
2328
- }
2329
- /**
2330
- * Called when the corresponding route is deactivated during navigation.
2331
- * Because the component get destroyed, all children outlet are destroyed.
2332
- */
2333
- onOutletDeactivated() {
2334
- const contexts = this.contexts;
2335
- this.contexts = new Map();
2336
- return contexts;
2337
- }
2338
- onOutletReAttached(contexts) {
2339
- this.contexts = contexts;
2340
- }
2341
- getOrCreateContext(childName) {
2342
- let context = this.getContext(childName);
2343
- if (!context) {
2344
- context = new OutletContext();
2345
- this.contexts.set(childName, context);
2346
- }
2347
- return context;
2348
- }
2349
- getContext(childName) {
2350
- return this.contexts.get(childName) || null;
2351
- }
2352
- }
2353
-
2354
- /**
2355
- * @license
2356
- * Copyright Google LLC All Rights Reserved.
2357
- *
2358
- * Use of this source code is governed by an MIT-style license that can be
2359
- * found in the LICENSE file at https://angular.io/license
2360
- */
2361
- /**
2362
- * @description
2363
- *
2364
- * Acts as a placeholder that Angular dynamically fills based on the current router state.
2365
- *
2366
- * Each outlet can have a unique name, determined by the optional `name` attribute.
2367
- * The name cannot be set or changed dynamically. If not set, default value is "primary".
2106
+ * Each outlet can have a unique name, determined by the optional `name` attribute.
2107
+ * The name cannot be set or changed dynamically. If not set, default value is "primary".
2368
2108
  *
2369
2109
  * ```
2370
2110
  * <router-outlet></router-outlet>
@@ -2410,11 +2150,11 @@ class ChildrenOutletContexts {
2410
2150
  * @publicApi
2411
2151
  */
2412
2152
  class RouterOutlet {
2413
- constructor(parentContexts, location, resolver, name, changeDetector) {
2153
+ constructor(parentContexts, location, name, changeDetector, environmentInjector) {
2414
2154
  this.parentContexts = parentContexts;
2415
2155
  this.location = location;
2416
- this.resolver = resolver;
2417
2156
  this.changeDetector = changeDetector;
2157
+ this.environmentInjector = environmentInjector;
2418
2158
  this.activated = null;
2419
2159
  this._activatedRoute = null;
2420
2160
  this.activateEvents = new EventEmitter();
@@ -2449,7 +2189,7 @@ class RouterOutlet {
2449
2189
  }
2450
2190
  else {
2451
2191
  // otherwise the component defined in the configuration is created
2452
- this.activateWith(context.route, context.resolver || null);
2192
+ this.activateWith(context.route, context.injector);
2453
2193
  }
2454
2194
  }
2455
2195
  }
@@ -2508,33 +2248,39 @@ class RouterOutlet {
2508
2248
  this.deactivateEvents.emit(c);
2509
2249
  }
2510
2250
  }
2511
- activateWith(activatedRoute, resolver) {
2251
+ activateWith(activatedRoute, resolverOrInjector) {
2512
2252
  if (this.isActivated) {
2513
2253
  throw new Error('Cannot activate an already activated outlet');
2514
2254
  }
2515
2255
  this._activatedRoute = activatedRoute;
2256
+ const location = this.location;
2516
2257
  const snapshot = activatedRoute._futureSnapshot;
2517
2258
  const component = snapshot.routeConfig.component;
2518
- resolver = resolver || this.resolver;
2519
- const factory = resolver.resolveComponentFactory(component);
2520
2259
  const childContexts = this.parentContexts.getOrCreateContext(this.name).children;
2521
- const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector);
2522
- this.activated = this.location.createComponent(factory, this.location.length, injector);
2260
+ const injector = new OutletInjector(activatedRoute, childContexts, location.injector);
2261
+ if (resolverOrInjector && isComponentFactoryResolver(resolverOrInjector)) {
2262
+ const factory = resolverOrInjector.resolveComponentFactory(component);
2263
+ this.activated = location.createComponent(factory, location.length, injector);
2264
+ }
2265
+ else {
2266
+ const environmentInjector = resolverOrInjector ?? this.environmentInjector;
2267
+ this.activated = location.createComponent(component, { index: location.length, injector, environmentInjector });
2268
+ }
2523
2269
  // Calling `markForCheck` to make sure we will run the change detection when the
2524
2270
  // `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
2525
2271
  this.changeDetector.markForCheck();
2526
2272
  this.activateEvents.emit(this.activated.instance);
2527
2273
  }
2528
2274
  }
2529
- RouterOutlet.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterOutlet, deps: [{ token: ChildrenOutletContexts }, { token: i0.ViewContainerRef }, { token: i0.ComponentFactoryResolver }, { token: 'name', attribute: true }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
2530
- RouterOutlet.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.11", type: RouterOutlet, selector: "router-outlet", outputs: { activateEvents: "activate", deactivateEvents: "deactivate", attachEvents: "attach", detachEvents: "detach" }, exportAs: ["outlet"], ngImport: i0 });
2531
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterOutlet, decorators: [{
2275
+ RouterOutlet.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterOutlet, deps: [{ token: ChildrenOutletContexts }, { token: i0.ViewContainerRef }, { token: 'name', attribute: true }, { token: i0.ChangeDetectorRef }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Directive });
2276
+ RouterOutlet.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.14", type: RouterOutlet, selector: "router-outlet", outputs: { activateEvents: "activate", deactivateEvents: "deactivate", attachEvents: "attach", detachEvents: "detach" }, exportAs: ["outlet"], ngImport: i0 });
2277
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterOutlet, decorators: [{
2532
2278
  type: Directive,
2533
2279
  args: [{ selector: 'router-outlet', exportAs: 'outlet' }]
2534
- }], ctorParameters: function () { return [{ type: ChildrenOutletContexts }, { type: i0.ViewContainerRef }, { type: i0.ComponentFactoryResolver }, { type: undefined, decorators: [{
2280
+ }], ctorParameters: function () { return [{ type: ChildrenOutletContexts }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
2535
2281
  type: Attribute,
2536
2282
  args: ['name']
2537
- }] }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { activateEvents: [{
2283
+ }] }, { type: i0.ChangeDetectorRef }, { type: i0.EnvironmentInjector }]; }, propDecorators: { activateEvents: [{
2538
2284
  type: Output,
2539
2285
  args: ['activate']
2540
2286
  }], deactivateEvents: [{
@@ -2553,14 +2299,376 @@ class OutletInjector {
2553
2299
  this.childContexts = childContexts;
2554
2300
  this.parent = parent;
2555
2301
  }
2556
- get(token, notFoundValue) {
2557
- if (token === ActivatedRoute) {
2558
- return this.route;
2302
+ get(token, notFoundValue) {
2303
+ if (token === ActivatedRoute) {
2304
+ return this.route;
2305
+ }
2306
+ if (token === ChildrenOutletContexts) {
2307
+ return this.childContexts;
2308
+ }
2309
+ return this.parent.get(token, notFoundValue);
2310
+ }
2311
+ }
2312
+ function isComponentFactoryResolver(item) {
2313
+ return !!item.resolveComponentFactory;
2314
+ }
2315
+
2316
+ /**
2317
+ * @license
2318
+ * Copyright Google LLC All Rights Reserved.
2319
+ *
2320
+ * Use of this source code is governed by an MIT-style license that can be
2321
+ * found in the LICENSE file at https://angular.io/license
2322
+ */
2323
+ /**
2324
+ * This component is used internally within the router to be a placeholder when an empty
2325
+ * router-outlet is needed. For example, with a config such as:
2326
+ *
2327
+ * `{path: 'parent', outlet: 'nav', children: [...]}`
2328
+ *
2329
+ * In order to render, there needs to be a component on this config, which will default
2330
+ * to this `EmptyOutletComponent`.
2331
+ */
2332
+ class ɵEmptyOutletComponent {
2333
+ }
2334
+ ɵEmptyOutletComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: ɵEmptyOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2335
+ ɵEmptyOutletComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "14.0.0-next.14", type: ɵEmptyOutletComponent, selector: "ng-component", ngImport: i0, template: `<router-outlet></router-outlet>`, isInline: true, dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
2336
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: ɵEmptyOutletComponent, decorators: [{
2337
+ type: Component,
2338
+ args: [{ template: `<router-outlet></router-outlet>` }]
2339
+ }] });
2340
+
2341
+ /**
2342
+ * @license
2343
+ * Copyright Google LLC All Rights Reserved.
2344
+ *
2345
+ * Use of this source code is governed by an MIT-style license that can be
2346
+ * found in the LICENSE file at https://angular.io/license
2347
+ */
2348
+ function getLoadedRoutes(route) {
2349
+ return route._loadedRoutes;
2350
+ }
2351
+ function getLoadedInjector(route) {
2352
+ return route._loadedInjector;
2353
+ }
2354
+ function getProvidersInjector(route) {
2355
+ return route._injector;
2356
+ }
2357
+ function validateConfig(config, parentPath = '') {
2358
+ // forEach doesn't iterate undefined values
2359
+ for (let i = 0; i < config.length; i++) {
2360
+ const route = config[i];
2361
+ const fullPath = getFullPath(parentPath, route);
2362
+ validateNode(route, fullPath);
2363
+ }
2364
+ }
2365
+ function validateNode(route, fullPath) {
2366
+ if (typeof ngDevMode === 'undefined' || ngDevMode) {
2367
+ if (!route) {
2368
+ throw new Error(`
2369
+ Invalid configuration of route '${fullPath}': Encountered undefined route.
2370
+ The reason might be an extra comma.
2371
+
2372
+ Example:
2373
+ const routes: Routes = [
2374
+ { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
2375
+ { path: 'dashboard', component: DashboardComponent },, << two commas
2376
+ { path: 'detail/:id', component: HeroDetailComponent }
2377
+ ];
2378
+ `);
2379
+ }
2380
+ if (Array.isArray(route)) {
2381
+ throw new Error(`Invalid configuration of route '${fullPath}': Array cannot be specified`);
2382
+ }
2383
+ if (!route.component && !route.children && !route.loadChildren &&
2384
+ (route.outlet && route.outlet !== PRIMARY_OUTLET)) {
2385
+ throw new Error(`Invalid configuration of route '${fullPath}': a componentless route without children or loadChildren cannot have a named outlet set`);
2386
+ }
2387
+ if (route.redirectTo && route.children) {
2388
+ throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and children cannot be used together`);
2389
+ }
2390
+ if (route.redirectTo && route.loadChildren) {
2391
+ throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and loadChildren cannot be used together`);
2392
+ }
2393
+ if (route.children && route.loadChildren) {
2394
+ throw new Error(`Invalid configuration of route '${fullPath}': children and loadChildren cannot be used together`);
2395
+ }
2396
+ if (route.redirectTo && route.component) {
2397
+ throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and component cannot be used together`);
2398
+ }
2399
+ if (route.redirectTo && route.canActivate) {
2400
+ throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and canActivate cannot be used together. Redirects happen before activation ` +
2401
+ `so canActivate will never be executed.`);
2402
+ }
2403
+ if (route.path && route.matcher) {
2404
+ throw new Error(`Invalid configuration of route '${fullPath}': path and matcher cannot be used together`);
2405
+ }
2406
+ if (route.redirectTo === void 0 && !route.component && !route.children && !route.loadChildren) {
2407
+ throw new Error(`Invalid configuration of route '${fullPath}'. One of the following must be provided: component, redirectTo, children or loadChildren`);
2408
+ }
2409
+ if (route.path === void 0 && route.matcher === void 0) {
2410
+ throw new Error(`Invalid configuration of route '${fullPath}': routes must have either a path or a matcher specified`);
2411
+ }
2412
+ if (typeof route.path === 'string' && route.path.charAt(0) === '/') {
2413
+ throw new Error(`Invalid configuration of route '${fullPath}': path cannot start with a slash`);
2414
+ }
2415
+ if (route.path === '' && route.redirectTo !== void 0 && route.pathMatch === void 0) {
2416
+ const exp = `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`;
2417
+ throw new Error(`Invalid configuration of route '{path: "${fullPath}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`);
2418
+ }
2419
+ }
2420
+ if (route.children) {
2421
+ validateConfig(route.children, fullPath);
2422
+ }
2423
+ }
2424
+ function getFullPath(parentPath, currentRoute) {
2425
+ if (!currentRoute) {
2426
+ return parentPath;
2427
+ }
2428
+ if (!parentPath && !currentRoute.path) {
2429
+ return '';
2430
+ }
2431
+ else if (parentPath && !currentRoute.path) {
2432
+ return `${parentPath}/`;
2433
+ }
2434
+ else if (!parentPath && currentRoute.path) {
2435
+ return currentRoute.path;
2436
+ }
2437
+ else {
2438
+ return `${parentPath}/${currentRoute.path}`;
2439
+ }
2440
+ }
2441
+ /**
2442
+ * Makes a copy of the config and adds any default required properties.
2443
+ */
2444
+ function standardizeConfig(r) {
2445
+ const children = r.children && r.children.map(standardizeConfig);
2446
+ const c = children ? { ...r, children } : { ...r };
2447
+ if (!c.component && (children || c.loadChildren) && (c.outlet && c.outlet !== PRIMARY_OUTLET)) {
2448
+ c.component = ɵEmptyOutletComponent;
2449
+ }
2450
+ return c;
2451
+ }
2452
+ /** Returns the `route.outlet` or PRIMARY_OUTLET if none exists. */
2453
+ function getOutlet(route) {
2454
+ return route.outlet || PRIMARY_OUTLET;
2455
+ }
2456
+ /**
2457
+ * Sorts the `routes` such that the ones with an outlet matching `outletName` come first.
2458
+ * The order of the configs is otherwise preserved.
2459
+ */
2460
+ function sortByMatchingOutlets(routes, outletName) {
2461
+ const sortedConfig = routes.filter(r => getOutlet(r) === outletName);
2462
+ sortedConfig.push(...routes.filter(r => getOutlet(r) !== outletName));
2463
+ return sortedConfig;
2464
+ }
2465
+ /**
2466
+ * Gets the first injector in the snapshot's parent tree.
2467
+ *
2468
+ * If the `Route` has a static list of providers, the returned injector will be the one created from
2469
+ * those. If it does not exist, the returned injector may come from the parents, which may be from a
2470
+ * loaded config or their static providers.
2471
+ *
2472
+ * Returns `null` if there is neither this nor any parents have a stored injector.
2473
+ *
2474
+ * Generally used for retrieving the injector to use for getting tokens for guards/resolvers and
2475
+ * also used for getting the correct injector to use for creating components.
2476
+ */
2477
+ function getClosestRouteInjector(snapshot) {
2478
+ if (!snapshot)
2479
+ return null;
2480
+ // If the current route has its own injector, which is created from the static providers on the
2481
+ // route itself, we should use that. Otherwise, we start at the parent since we do not want to
2482
+ // include the lazy loaded injector from this route.
2483
+ if (snapshot.routeConfig?._injector) {
2484
+ return snapshot.routeConfig._injector;
2485
+ }
2486
+ for (let s = snapshot.parent; s; s = s.parent) {
2487
+ const route = s.routeConfig;
2488
+ // Note that the order here is important. `_loadedInjector` stored on the route with
2489
+ // `loadChildren: () => NgModule` so it applies to child routes with priority. The `_injector`
2490
+ // is created from the static providers on that parent route, so it applies to the children as
2491
+ // well, but only if there is no lazy loaded NgModuleRef injector.
2492
+ if (route?._loadedInjector)
2493
+ return route._loadedInjector;
2494
+ if (route?._injector)
2495
+ return route._injector;
2496
+ }
2497
+ return null;
2498
+ }
2499
+
2500
+ /**
2501
+ * @license
2502
+ * Copyright Google LLC All Rights Reserved.
2503
+ *
2504
+ * Use of this source code is governed by an MIT-style license that can be
2505
+ * found in the LICENSE file at https://angular.io/license
2506
+ */
2507
+ const activateRoutes = (rootContexts, routeReuseStrategy, forwardEvent) => map(t => {
2508
+ new ActivateRoutes(routeReuseStrategy, t.targetRouterState, t.currentRouterState, forwardEvent)
2509
+ .activate(rootContexts);
2510
+ return t;
2511
+ });
2512
+ class ActivateRoutes {
2513
+ constructor(routeReuseStrategy, futureState, currState, forwardEvent) {
2514
+ this.routeReuseStrategy = routeReuseStrategy;
2515
+ this.futureState = futureState;
2516
+ this.currState = currState;
2517
+ this.forwardEvent = forwardEvent;
2518
+ }
2519
+ activate(parentContexts) {
2520
+ const futureRoot = this.futureState._root;
2521
+ const currRoot = this.currState ? this.currState._root : null;
2522
+ this.deactivateChildRoutes(futureRoot, currRoot, parentContexts);
2523
+ advanceActivatedRoute(this.futureState.root);
2524
+ this.activateChildRoutes(futureRoot, currRoot, parentContexts);
2525
+ }
2526
+ // De-activate the child route that are not re-used for the future state
2527
+ deactivateChildRoutes(futureNode, currNode, contexts) {
2528
+ const children = nodeChildrenAsMap(currNode);
2529
+ // Recurse on the routes active in the future state to de-activate deeper children
2530
+ futureNode.children.forEach(futureChild => {
2531
+ const childOutletName = futureChild.value.outlet;
2532
+ this.deactivateRoutes(futureChild, children[childOutletName], contexts);
2533
+ delete children[childOutletName];
2534
+ });
2535
+ // De-activate the routes that will not be re-used
2536
+ forEach(children, (v, childName) => {
2537
+ this.deactivateRouteAndItsChildren(v, contexts);
2538
+ });
2539
+ }
2540
+ deactivateRoutes(futureNode, currNode, parentContext) {
2541
+ const future = futureNode.value;
2542
+ const curr = currNode ? currNode.value : null;
2543
+ if (future === curr) {
2544
+ // Reusing the node, check to see if the children need to be de-activated
2545
+ if (future.component) {
2546
+ // If we have a normal route, we need to go through an outlet.
2547
+ const context = parentContext.getContext(future.outlet);
2548
+ if (context) {
2549
+ this.deactivateChildRoutes(futureNode, currNode, context.children);
2550
+ }
2551
+ }
2552
+ else {
2553
+ // if we have a componentless route, we recurse but keep the same outlet map.
2554
+ this.deactivateChildRoutes(futureNode, currNode, parentContext);
2555
+ }
2556
+ }
2557
+ else {
2558
+ if (curr) {
2559
+ // Deactivate the current route which will not be re-used
2560
+ this.deactivateRouteAndItsChildren(currNode, parentContext);
2561
+ }
2562
+ }
2563
+ }
2564
+ deactivateRouteAndItsChildren(route, parentContexts) {
2565
+ // If there is no component, the Route is never attached to an outlet (because there is no
2566
+ // component to attach).
2567
+ if (route.value.component && this.routeReuseStrategy.shouldDetach(route.value.snapshot)) {
2568
+ this.detachAndStoreRouteSubtree(route, parentContexts);
2569
+ }
2570
+ else {
2571
+ this.deactivateRouteAndOutlet(route, parentContexts);
2572
+ }
2573
+ }
2574
+ detachAndStoreRouteSubtree(route, parentContexts) {
2575
+ const context = parentContexts.getContext(route.value.outlet);
2576
+ const contexts = context && route.value.component ? context.children : parentContexts;
2577
+ const children = nodeChildrenAsMap(route);
2578
+ for (const childOutlet of Object.keys(children)) {
2579
+ this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2580
+ }
2581
+ if (context && context.outlet) {
2582
+ const componentRef = context.outlet.detach();
2583
+ const contexts = context.children.onOutletDeactivated();
2584
+ this.routeReuseStrategy.store(route.value.snapshot, { componentRef, route, contexts });
2585
+ }
2586
+ }
2587
+ deactivateRouteAndOutlet(route, parentContexts) {
2588
+ const context = parentContexts.getContext(route.value.outlet);
2589
+ // The context could be `null` if we are on a componentless route but there may still be
2590
+ // children that need deactivating.
2591
+ const contexts = context && route.value.component ? context.children : parentContexts;
2592
+ const children = nodeChildrenAsMap(route);
2593
+ for (const childOutlet of Object.keys(children)) {
2594
+ this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
2595
+ }
2596
+ if (context && context.outlet) {
2597
+ // Destroy the component
2598
+ context.outlet.deactivate();
2599
+ // Destroy the contexts for all the outlets that were in the component
2600
+ context.children.onOutletDeactivated();
2601
+ // Clear the information about the attached component on the context but keep the reference to
2602
+ // the outlet.
2603
+ context.attachRef = null;
2604
+ context.resolver = null;
2605
+ context.route = null;
2606
+ }
2607
+ }
2608
+ activateChildRoutes(futureNode, currNode, contexts) {
2609
+ const children = nodeChildrenAsMap(currNode);
2610
+ futureNode.children.forEach(c => {
2611
+ this.activateRoutes(c, children[c.value.outlet], contexts);
2612
+ this.forwardEvent(new ActivationEnd(c.value.snapshot));
2613
+ });
2614
+ if (futureNode.children.length) {
2615
+ this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));
2616
+ }
2617
+ }
2618
+ activateRoutes(futureNode, currNode, parentContexts) {
2619
+ const future = futureNode.value;
2620
+ const curr = currNode ? currNode.value : null;
2621
+ advanceActivatedRoute(future);
2622
+ // reusing the node
2623
+ if (future === curr) {
2624
+ if (future.component) {
2625
+ // If we have a normal route, we need to go through an outlet.
2626
+ const context = parentContexts.getOrCreateContext(future.outlet);
2627
+ this.activateChildRoutes(futureNode, currNode, context.children);
2628
+ }
2629
+ else {
2630
+ // if we have a componentless route, we recurse but keep the same outlet map.
2631
+ this.activateChildRoutes(futureNode, currNode, parentContexts);
2632
+ }
2559
2633
  }
2560
- if (token === ChildrenOutletContexts) {
2561
- return this.childContexts;
2634
+ else {
2635
+ if (future.component) {
2636
+ // if we have a normal route, we need to place the component into the outlet and recurse.
2637
+ const context = parentContexts.getOrCreateContext(future.outlet);
2638
+ if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
2639
+ const stored = this.routeReuseStrategy.retrieve(future.snapshot);
2640
+ this.routeReuseStrategy.store(future.snapshot, null);
2641
+ context.children.onOutletReAttached(stored.contexts);
2642
+ context.attachRef = stored.componentRef;
2643
+ context.route = stored.route.value;
2644
+ if (context.outlet) {
2645
+ // Attach right away when the outlet has already been instantiated
2646
+ // Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated
2647
+ context.outlet.attach(stored.componentRef, stored.route.value);
2648
+ }
2649
+ advanceActivatedRoute(stored.route.value);
2650
+ this.activateChildRoutes(futureNode, null, context.children);
2651
+ }
2652
+ else {
2653
+ const injector = getClosestRouteInjector(future.snapshot);
2654
+ const cmpFactoryResolver = injector?.get(ComponentFactoryResolver) ?? null;
2655
+ context.attachRef = null;
2656
+ context.route = future;
2657
+ context.resolver = cmpFactoryResolver;
2658
+ context.injector = injector;
2659
+ if (context.outlet) {
2660
+ // Activate the outlet when it has already been instantiated
2661
+ // Otherwise it will get activated from its `ngOnInit` when instantiated
2662
+ context.outlet.activateWith(future, context.injector);
2663
+ }
2664
+ this.activateChildRoutes(futureNode, null, context.children);
2665
+ }
2666
+ }
2667
+ else {
2668
+ // if we have a componentless route, we recurse but keep the same outlet map.
2669
+ this.activateChildRoutes(futureNode, null, parentContexts);
2670
+ }
2562
2671
  }
2563
- return this.parent.get(token, notFoundValue);
2564
2672
  }
2565
2673
  }
2566
2674
 
@@ -2572,22 +2680,39 @@ class OutletInjector {
2572
2680
  * found in the LICENSE file at https://angular.io/license
2573
2681
  */
2574
2682
  /**
2575
- * This component is used internally within the router to be a placeholder when an empty
2576
- * router-outlet is needed. For example, with a config such as:
2683
+ * Simple function check, but generic so type inference will flow. Example:
2577
2684
  *
2578
- * `{path: 'parent', outlet: 'nav', children: [...]}`
2685
+ * function product(a: number, b: number) {
2686
+ * return a * b;
2687
+ * }
2579
2688
  *
2580
- * In order to render, there needs to be a component on this config, which will default
2581
- * to this `EmptyOutletComponent`.
2689
+ * if (isFunction<product>(fn)) {
2690
+ * return fn(1, 2);
2691
+ * } else {
2692
+ * throw "Must provide the `product` function";
2693
+ * }
2582
2694
  */
2583
- class ɵEmptyOutletComponent {
2695
+ function isFunction(v) {
2696
+ return typeof v === 'function';
2697
+ }
2698
+ function isBoolean(v) {
2699
+ return typeof v === 'boolean';
2700
+ }
2701
+ function isUrlTree(v) {
2702
+ return v instanceof UrlTree;
2703
+ }
2704
+ function isCanLoad(guard) {
2705
+ return guard && isFunction(guard.canLoad);
2706
+ }
2707
+ function isCanActivate(guard) {
2708
+ return guard && isFunction(guard.canActivate);
2709
+ }
2710
+ function isCanActivateChild(guard) {
2711
+ return guard && isFunction(guard.canActivateChild);
2712
+ }
2713
+ function isCanDeactivate(guard) {
2714
+ return guard && isFunction(guard.canDeactivate);
2584
2715
  }
2585
- ɵEmptyOutletComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: ɵEmptyOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2586
- ɵEmptyOutletComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "14.0.0-next.11", type: ɵEmptyOutletComponent, selector: "ng-component", ngImport: i0, template: `<router-outlet></router-outlet>`, isInline: true, directives: [{ type: RouterOutlet, selector: "router-outlet", outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }] });
2587
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: ɵEmptyOutletComponent, decorators: [{
2588
- type: Component,
2589
- args: [{ template: `<router-outlet></router-outlet>` }]
2590
- }] });
2591
2716
 
2592
2717
  /**
2593
2718
  * @license
@@ -2596,113 +2721,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11",
2596
2721
  * Use of this source code is governed by an MIT-style license that can be
2597
2722
  * found in the LICENSE file at https://angular.io/license
2598
2723
  */
2599
- function validateConfig(config, parentPath = '') {
2600
- // forEach doesn't iterate undefined values
2601
- for (let i = 0; i < config.length; i++) {
2602
- const route = config[i];
2603
- const fullPath = getFullPath(parentPath, route);
2604
- validateNode(route, fullPath);
2605
- }
2606
- }
2607
- function validateNode(route, fullPath) {
2608
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
2609
- if (!route) {
2610
- throw new Error(`
2611
- Invalid configuration of route '${fullPath}': Encountered undefined route.
2612
- The reason might be an extra comma.
2613
-
2614
- Example:
2615
- const routes: Routes = [
2616
- { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
2617
- { path: 'dashboard', component: DashboardComponent },, << two commas
2618
- { path: 'detail/:id', component: HeroDetailComponent }
2619
- ];
2620
- `);
2621
- }
2622
- if (Array.isArray(route)) {
2623
- throw new Error(`Invalid configuration of route '${fullPath}': Array cannot be specified`);
2624
- }
2625
- if (!route.component && !route.children && !route.loadChildren &&
2626
- (route.outlet && route.outlet !== PRIMARY_OUTLET)) {
2627
- throw new Error(`Invalid configuration of route '${fullPath}': a componentless route without children or loadChildren cannot have a named outlet set`);
2628
- }
2629
- if (route.redirectTo && route.children) {
2630
- throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and children cannot be used together`);
2631
- }
2632
- if (route.redirectTo && route.loadChildren) {
2633
- throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and loadChildren cannot be used together`);
2634
- }
2635
- if (route.children && route.loadChildren) {
2636
- throw new Error(`Invalid configuration of route '${fullPath}': children and loadChildren cannot be used together`);
2637
- }
2638
- if (route.redirectTo && route.component) {
2639
- throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and component cannot be used together`);
2640
- }
2641
- if (route.redirectTo && route.canActivate) {
2642
- throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and canActivate cannot be used together. Redirects happen before activation ` +
2643
- `so canActivate will never be executed.`);
2644
- }
2645
- if (route.path && route.matcher) {
2646
- throw new Error(`Invalid configuration of route '${fullPath}': path and matcher cannot be used together`);
2647
- }
2648
- if (route.redirectTo === void 0 && !route.component && !route.children && !route.loadChildren) {
2649
- throw new Error(`Invalid configuration of route '${fullPath}'. One of the following must be provided: component, redirectTo, children or loadChildren`);
2650
- }
2651
- if (route.path === void 0 && route.matcher === void 0) {
2652
- throw new Error(`Invalid configuration of route '${fullPath}': routes must have either a path or a matcher specified`);
2653
- }
2654
- if (typeof route.path === 'string' && route.path.charAt(0) === '/') {
2655
- throw new Error(`Invalid configuration of route '${fullPath}': path cannot start with a slash`);
2656
- }
2657
- if (route.path === '' && route.redirectTo !== void 0 && route.pathMatch === void 0) {
2658
- const exp = `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`;
2659
- throw new Error(`Invalid configuration of route '{path: "${fullPath}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`);
2660
- }
2661
- }
2662
- if (route.children) {
2663
- validateConfig(route.children, fullPath);
2664
- }
2665
- }
2666
- function getFullPath(parentPath, currentRoute) {
2667
- if (!currentRoute) {
2668
- return parentPath;
2669
- }
2670
- if (!parentPath && !currentRoute.path) {
2671
- return '';
2672
- }
2673
- else if (parentPath && !currentRoute.path) {
2674
- return `${parentPath}/`;
2675
- }
2676
- else if (!parentPath && currentRoute.path) {
2677
- return currentRoute.path;
2678
- }
2679
- else {
2680
- return `${parentPath}/${currentRoute.path}`;
2681
- }
2682
- }
2683
- /**
2684
- * Makes a copy of the config and adds any default required properties.
2685
- */
2686
- function standardizeConfig(r) {
2687
- const children = r.children && r.children.map(standardizeConfig);
2688
- const c = children ? { ...r, children } : { ...r };
2689
- if (!c.component && (children || c.loadChildren) && (c.outlet && c.outlet !== PRIMARY_OUTLET)) {
2690
- c.component = ɵEmptyOutletComponent;
2691
- }
2692
- return c;
2693
- }
2694
- /** Returns the `route.outlet` or PRIMARY_OUTLET if none exists. */
2695
- function getOutlet(route) {
2696
- return route.outlet || PRIMARY_OUTLET;
2697
- }
2698
- /**
2699
- * Sorts the `routes` such that the ones with an outlet matching `outletName` come first.
2700
- * The order of the configs is otherwise preserved.
2701
- */
2702
- function sortByMatchingOutlets(routes, outletName) {
2703
- const sortedConfig = routes.filter(r => getOutlet(r) === outletName);
2704
- sortedConfig.push(...routes.filter(r => getOutlet(r) !== outletName));
2705
- return sortedConfig;
2724
+ const INITIAL_VALUE = Symbol('INITIAL_VALUE');
2725
+ function prioritizedGuardValue() {
2726
+ return switchMap(obs => {
2727
+ return combineLatest(obs.map(o => o.pipe(take(1), startWith(INITIAL_VALUE))))
2728
+ .pipe(scan((acc, list) => {
2729
+ let isPending = false;
2730
+ return list.reduce((innerAcc, val, i) => {
2731
+ if (innerAcc !== INITIAL_VALUE)
2732
+ return innerAcc;
2733
+ // Toggle pending flag if any values haven't been set yet
2734
+ if (val === INITIAL_VALUE)
2735
+ isPending = true;
2736
+ // Any other return values are only valid if we haven't yet hit a pending
2737
+ // call. This guarantees that in the case of a guard at the bottom of the
2738
+ // tree that returns a redirect, we will wait for the higher priority
2739
+ // guard at the top to finish before performing the redirect.
2740
+ if (!isPending) {
2741
+ // Early return when we hit a `false` value as that should always
2742
+ // cancel navigation
2743
+ if (val === false)
2744
+ return val;
2745
+ if (i === list.length - 1 || isUrlTree(val)) {
2746
+ return val;
2747
+ }
2748
+ }
2749
+ return innerAcc;
2750
+ }, acc);
2751
+ }, INITIAL_VALUE), filter(item => item !== INITIAL_VALUE), map(item => isUrlTree(item) ? item : item === true), //
2752
+ take(1));
2753
+ });
2706
2754
  }
2707
2755
 
2708
2756
  /**
@@ -2780,6 +2828,9 @@ function addEmptyPathsToChildrenIfNeeded(segmentGroup, consumedSegments, slicedS
2780
2828
  s._sourceSegment = segmentGroup;
2781
2829
  if (relativeLinkResolution === 'legacy') {
2782
2830
  s._segmentIndexShift = segmentGroup.segments.length;
2831
+ if (typeof ngDevMode === 'undefined' || !!ngDevMode) {
2832
+ s._segmentIndexShiftCorrected = consumedSegments.length;
2833
+ }
2783
2834
  }
2784
2835
  else {
2785
2836
  s._segmentIndexShift = consumedSegments.length;
@@ -2880,17 +2931,17 @@ function canLoadFails(route) {
2880
2931
  *
2881
2932
  * Lazy modules are loaded along the way.
2882
2933
  */
2883
- function applyRedirects$1(moduleInjector, configLoader, urlSerializer, urlTree, config) {
2884
- return new ApplyRedirects(moduleInjector, configLoader, urlSerializer, urlTree, config).apply();
2934
+ function applyRedirects$1(injector, configLoader, urlSerializer, urlTree, config) {
2935
+ return new ApplyRedirects(injector, configLoader, urlSerializer, urlTree, config).apply();
2885
2936
  }
2886
2937
  class ApplyRedirects {
2887
- constructor(moduleInjector, configLoader, urlSerializer, urlTree, config) {
2938
+ constructor(injector, configLoader, urlSerializer, urlTree, config) {
2939
+ this.injector = injector;
2888
2940
  this.configLoader = configLoader;
2889
2941
  this.urlSerializer = urlSerializer;
2890
2942
  this.urlTree = urlTree;
2891
2943
  this.config = config;
2892
2944
  this.allowRedirects = true;
2893
- this.ngModule = moduleInjector.get(NgModuleRef);
2894
2945
  }
2895
2946
  apply() {
2896
2947
  const splitGroup = split(this.urlTree.root, [], [], this.config).segmentGroup;
@@ -2901,7 +2952,7 @@ class ApplyRedirects {
2901
2952
  // them. We should be able to remove this logic as a "breaking change" but should do some more
2902
2953
  // investigation into the failures first.
2903
2954
  const rootSegmentGroup = new UrlSegmentGroup(splitGroup.segments, splitGroup.children);
2904
- const expanded$ = this.expandSegmentGroup(this.ngModule, this.config, rootSegmentGroup, PRIMARY_OUTLET);
2955
+ const expanded$ = this.expandSegmentGroup(this.injector, this.config, rootSegmentGroup, PRIMARY_OUTLET);
2905
2956
  const urlTrees$ = expanded$.pipe(map((rootSegmentGroup) => {
2906
2957
  return this.createUrlTree(squashSegmentGroup(rootSegmentGroup), this.urlTree.queryParams, this.urlTree.fragment);
2907
2958
  }));
@@ -2920,7 +2971,7 @@ class ApplyRedirects {
2920
2971
  }));
2921
2972
  }
2922
2973
  match(tree) {
2923
- const expanded$ = this.expandSegmentGroup(this.ngModule, this.config, tree.root, PRIMARY_OUTLET);
2974
+ const expanded$ = this.expandSegmentGroup(this.injector, this.config, tree.root, PRIMARY_OUTLET);
2924
2975
  const mapped$ = expanded$.pipe(map((rootSegmentGroup) => {
2925
2976
  return this.createUrlTree(squashSegmentGroup(rootSegmentGroup), tree.queryParams, tree.fragment);
2926
2977
  }));
@@ -2940,15 +2991,15 @@ class ApplyRedirects {
2940
2991
  rootCandidate;
2941
2992
  return new UrlTree(root, queryParams, fragment);
2942
2993
  }
2943
- expandSegmentGroup(ngModule, routes, segmentGroup, outlet) {
2994
+ expandSegmentGroup(injector, routes, segmentGroup, outlet) {
2944
2995
  if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
2945
- return this.expandChildren(ngModule, routes, segmentGroup)
2996
+ return this.expandChildren(injector, routes, segmentGroup)
2946
2997
  .pipe(map((children) => new UrlSegmentGroup([], children)));
2947
2998
  }
2948
- return this.expandSegment(ngModule, segmentGroup, routes, segmentGroup.segments, outlet, true);
2999
+ return this.expandSegment(injector, segmentGroup, routes, segmentGroup.segments, outlet, true);
2949
3000
  }
2950
3001
  // Recursively expand segment groups for all the child outlets
2951
- expandChildren(ngModule, routes, segmentGroup) {
3002
+ expandChildren(injector, routes, segmentGroup) {
2952
3003
  // Expand outlets one at a time, starting with the primary outlet. We need to do it this way
2953
3004
  // because an absolute redirect from the primary outlet takes precedence.
2954
3005
  const childOutlets = [];
@@ -2967,16 +3018,25 @@ class ApplyRedirects {
2967
3018
  // first, followed by routes for other outlets, which might match if they have an
2968
3019
  // empty path.
2969
3020
  const sortedRoutes = sortByMatchingOutlets(routes, childOutlet);
2970
- return this.expandSegmentGroup(ngModule, sortedRoutes, child, childOutlet)
3021
+ return this.expandSegmentGroup(injector, sortedRoutes, child, childOutlet)
2971
3022
  .pipe(map(s => ({ segment: s, outlet: childOutlet })));
2972
3023
  }), scan((children, expandedChild) => {
2973
3024
  children[expandedChild.outlet] = expandedChild.segment;
2974
3025
  return children;
2975
3026
  }, {}), last$1());
2976
3027
  }
2977
- expandSegment(ngModule, segmentGroup, routes, segments, outlet, allowRedirects) {
2978
- return from(routes).pipe(concatMap((r) => {
2979
- const expanded$ = this.expandSegmentAgainstRoute(ngModule, segmentGroup, routes, r, segments, outlet, allowRedirects);
3028
+ expandSegment(injector, segmentGroup, routes, segments, outlet, allowRedirects) {
3029
+ return from(routes).pipe(concatMap(r => {
3030
+ if (r.providers && !r._injector) {
3031
+ r._injector = createEnvironmentInjector(r.providers, injector, `Route: ${r.path}`);
3032
+ }
3033
+ // We specifically _do not_ want to include the _loadedInjector here. The loaded injector
3034
+ // only applies to the route's children, not the route itself. Note that this distinction
3035
+ // only applies here to any tokens we try to retrieve during this phase. At the moment,
3036
+ // that only includes `canLoad`, which won't run again once the child module is loaded. As
3037
+ // a result, this makes no difference right now, but could in the future if there are more
3038
+ // actions here that need DI (for example, a canMatch guard).
3039
+ const expanded$ = this.expandSegmentAgainstRoute(r._injector ?? injector, segmentGroup, routes, r, segments, outlet, allowRedirects);
2980
3040
  return expanded$.pipe(catchError((e) => {
2981
3041
  if (e instanceof NoMatch$1) {
2982
3042
  return of(null);
@@ -2993,35 +3053,35 @@ class ApplyRedirects {
2993
3053
  throw e;
2994
3054
  }));
2995
3055
  }
2996
- expandSegmentAgainstRoute(ngModule, segmentGroup, routes, route, paths, outlet, allowRedirects) {
3056
+ expandSegmentAgainstRoute(injector, segmentGroup, routes, route, paths, outlet, allowRedirects) {
2997
3057
  if (!isImmediateMatch(route, segmentGroup, paths, outlet)) {
2998
3058
  return noMatch(segmentGroup);
2999
3059
  }
3000
3060
  if (route.redirectTo === undefined) {
3001
- return this.matchSegmentAgainstRoute(ngModule, segmentGroup, route, paths, outlet);
3061
+ return this.matchSegmentAgainstRoute(injector, segmentGroup, route, paths, outlet);
3002
3062
  }
3003
3063
  if (allowRedirects && this.allowRedirects) {
3004
- return this.expandSegmentAgainstRouteUsingRedirect(ngModule, segmentGroup, routes, route, paths, outlet);
3064
+ return this.expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, paths, outlet);
3005
3065
  }
3006
3066
  return noMatch(segmentGroup);
3007
3067
  }
3008
- expandSegmentAgainstRouteUsingRedirect(ngModule, segmentGroup, routes, route, segments, outlet) {
3068
+ expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
3009
3069
  if (route.path === '**') {
3010
- return this.expandWildCardWithParamsAgainstRouteUsingRedirect(ngModule, routes, route, outlet);
3070
+ return this.expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet);
3011
3071
  }
3012
- return this.expandRegularSegmentAgainstRouteUsingRedirect(ngModule, segmentGroup, routes, route, segments, outlet);
3072
+ return this.expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet);
3013
3073
  }
3014
- expandWildCardWithParamsAgainstRouteUsingRedirect(ngModule, routes, route, outlet) {
3074
+ expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet) {
3015
3075
  const newTree = this.applyRedirectCommands([], route.redirectTo, {});
3016
3076
  if (route.redirectTo.startsWith('/')) {
3017
3077
  return absoluteRedirect(newTree);
3018
3078
  }
3019
3079
  return this.lineralizeSegments(route, newTree).pipe(mergeMap((newSegments) => {
3020
3080
  const group = new UrlSegmentGroup(newSegments, {});
3021
- return this.expandSegment(ngModule, group, routes, newSegments, outlet, false);
3081
+ return this.expandSegment(injector, group, routes, newSegments, outlet, false);
3022
3082
  }));
3023
3083
  }
3024
- expandRegularSegmentAgainstRouteUsingRedirect(ngModule, segmentGroup, routes, route, segments, outlet) {
3084
+ expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
3025
3085
  const { matched, consumedSegments, remainingSegments, positionalParamSegments } = match(segmentGroup, route, segments);
3026
3086
  if (!matched)
3027
3087
  return noMatch(segmentGroup);
@@ -3030,16 +3090,18 @@ class ApplyRedirects {
3030
3090
  return absoluteRedirect(newTree);
3031
3091
  }
3032
3092
  return this.lineralizeSegments(route, newTree).pipe(mergeMap((newSegments) => {
3033
- return this.expandSegment(ngModule, segmentGroup, routes, newSegments.concat(remainingSegments), outlet, false);
3093
+ return this.expandSegment(injector, segmentGroup, routes, newSegments.concat(remainingSegments), outlet, false);
3034
3094
  }));
3035
3095
  }
3036
- matchSegmentAgainstRoute(ngModule, rawSegmentGroup, route, segments, outlet) {
3096
+ matchSegmentAgainstRoute(injector, rawSegmentGroup, route, segments, outlet) {
3037
3097
  if (route.path === '**') {
3038
3098
  if (route.loadChildren) {
3039
- const loaded$ = route._loadedConfig ? of(route._loadedConfig) :
3040
- this.configLoader.load(ngModule.injector, route);
3099
+ const loaded$ = route._loadedRoutes ?
3100
+ of({ routes: route._loadedRoutes, injector: route._loadedInjector }) :
3101
+ this.configLoader.load(injector, route);
3041
3102
  return loaded$.pipe(map((cfg) => {
3042
- route._loadedConfig = cfg;
3103
+ route._loadedRoutes = cfg.routes;
3104
+ route._loadedInjector = cfg.injector;
3043
3105
  return new UrlSegmentGroup(segments, {});
3044
3106
  }));
3045
3107
  }
@@ -3048,55 +3110,55 @@ class ApplyRedirects {
3048
3110
  const { matched, consumedSegments, remainingSegments } = match(rawSegmentGroup, route, segments);
3049
3111
  if (!matched)
3050
3112
  return noMatch(rawSegmentGroup);
3051
- const childConfig$ = this.getChildConfig(ngModule, route, segments);
3113
+ const childConfig$ = this.getChildConfig(injector, route, segments);
3052
3114
  return childConfig$.pipe(mergeMap((routerConfig) => {
3053
- const childModule = routerConfig.module;
3115
+ const childInjector = routerConfig.injector ?? injector;
3054
3116
  const childConfig = routerConfig.routes;
3055
3117
  const { segmentGroup: splitSegmentGroup, slicedSegments } = split(rawSegmentGroup, consumedSegments, remainingSegments, childConfig);
3056
3118
  // See comment on the other call to `split` about why this is necessary.
3057
3119
  const segmentGroup = new UrlSegmentGroup(splitSegmentGroup.segments, splitSegmentGroup.children);
3058
3120
  if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
3059
- const expanded$ = this.expandChildren(childModule, childConfig, segmentGroup);
3121
+ const expanded$ = this.expandChildren(childInjector, childConfig, segmentGroup);
3060
3122
  return expanded$.pipe(map((children) => new UrlSegmentGroup(consumedSegments, children)));
3061
3123
  }
3062
3124
  if (childConfig.length === 0 && slicedSegments.length === 0) {
3063
3125
  return of(new UrlSegmentGroup(consumedSegments, {}));
3064
3126
  }
3065
3127
  const matchedOnOutlet = getOutlet(route) === outlet;
3066
- const expanded$ = this.expandSegment(childModule, segmentGroup, childConfig, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
3128
+ const expanded$ = this.expandSegment(childInjector, segmentGroup, childConfig, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
3067
3129
  return expanded$.pipe(map((cs) => new UrlSegmentGroup(consumedSegments.concat(cs.segments), cs.children)));
3068
3130
  }));
3069
3131
  }
3070
- getChildConfig(ngModule, route, segments) {
3132
+ getChildConfig(injector, route, segments) {
3071
3133
  if (route.children) {
3072
3134
  // The children belong to the same module
3073
- return of(new LoadedRouterConfig(route.children, ngModule));
3135
+ return of({ routes: route.children, injector });
3074
3136
  }
3075
3137
  if (route.loadChildren) {
3076
3138
  // lazy children belong to the loaded module
3077
- if (route._loadedConfig !== undefined) {
3078
- return of(route._loadedConfig);
3139
+ if (route._loadedRoutes !== undefined) {
3140
+ return of({ routes: route._loadedRoutes, injector: route._loadedInjector });
3079
3141
  }
3080
- return this.runCanLoadGuards(ngModule.injector, route, segments)
3142
+ return this.runCanLoadGuards(injector, route, segments)
3081
3143
  .pipe(mergeMap((shouldLoadResult) => {
3082
3144
  if (shouldLoadResult) {
3083
- return this.configLoader.load(ngModule.injector, route)
3084
- .pipe(map((cfg) => {
3085
- route._loadedConfig = cfg;
3145
+ return this.configLoader.load(injector, route).pipe(map((cfg) => {
3146
+ route._loadedRoutes = cfg.routes;
3147
+ route._loadedInjector = cfg.injector;
3086
3148
  return cfg;
3087
3149
  }));
3088
3150
  }
3089
3151
  return canLoadFails(route);
3090
3152
  }));
3091
3153
  }
3092
- return of(new LoadedRouterConfig([], ngModule));
3154
+ return of({ routes: [], injector });
3093
3155
  }
3094
- runCanLoadGuards(moduleInjector, route, segments) {
3156
+ runCanLoadGuards(injector, route, segments) {
3095
3157
  const canLoad = route.canLoad;
3096
3158
  if (!canLoad || canLoad.length === 0)
3097
3159
  return of(true);
3098
3160
  const canLoadObservables = canLoad.map((injectionToken) => {
3099
- const guard = moduleInjector.get(injectionToken);
3161
+ const guard = injector.get(injectionToken);
3100
3162
  let guardVal;
3101
3163
  if (isCanLoad(guard)) {
3102
3164
  guardVal = guard.canLoad(route, segments);
@@ -3224,8 +3286,8 @@ function squashSegmentGroup(segmentGroup) {
3224
3286
  * Use of this source code is governed by an MIT-style license that can be
3225
3287
  * found in the LICENSE file at https://angular.io/license
3226
3288
  */
3227
- function applyRedirects(moduleInjector, configLoader, urlSerializer, config) {
3228
- return switchMap(t => applyRedirects$1(moduleInjector, configLoader, urlSerializer, t.extractedUrl, config)
3289
+ function applyRedirects(environmentInjector, configLoader, urlSerializer, config) {
3290
+ return switchMap(t => applyRedirects$1(environmentInjector, configLoader, urlSerializer, t.extractedUrl, config)
3229
3291
  .pipe(map(urlAfterRedirects => ({ ...t, urlAfterRedirects }))));
3230
3292
  }
3231
3293
 
@@ -3259,21 +3321,11 @@ function getCanActivateChild(p) {
3259
3321
  return null;
3260
3322
  return { node: p, guards: canActivateChild };
3261
3323
  }
3262
- function getToken(token, snapshot, moduleInjector) {
3263
- const config = getClosestLoadedConfig(snapshot);
3264
- const injector = config ? config.module.injector : moduleInjector;
3324
+ function getToken(token, snapshot, fallbackInjector) {
3325
+ const routeInjector = getClosestRouteInjector(snapshot);
3326
+ const injector = routeInjector ?? fallbackInjector;
3265
3327
  return injector.get(token);
3266
3328
  }
3267
- function getClosestLoadedConfig(snapshot) {
3268
- if (!snapshot)
3269
- return null;
3270
- for (let s = snapshot.parent; s; s = s.parent) {
3271
- const route = s.routeConfig;
3272
- if (route && route._loadedConfig)
3273
- return route._loadedConfig;
3274
- }
3275
- return null;
3276
- }
3277
3329
  function getChildRouteGuards(futureNode, currNode, contexts, futurePath, checks = {
3278
3330
  canDeactivateChecks: [],
3279
3331
  canActivateChecks: []
@@ -3517,6 +3569,7 @@ function runCanDeactivate(component, currARS, currRSS, futureRSS, moduleInjector
3517
3569
  * Use of this source code is governed by an MIT-style license that can be
3518
3570
  * found in the LICENSE file at https://angular.io/license
3519
3571
  */
3572
+ const NG_DEV_MODE$2 = typeof ngDevMode === 'undefined' || !!ngDevMode;
3520
3573
  class NoMatch {
3521
3574
  }
3522
3575
  function newObservableError(e) {
@@ -3632,7 +3685,13 @@ class Recognizer {
3632
3685
  let remainingSegments = [];
3633
3686
  if (route.path === '**') {
3634
3687
  const params = segments.length > 0 ? last(segments).parameters : {};
3635
- snapshot = new ActivatedRouteSnapshot(segments, params, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + segments.length, getResolve(route));
3688
+ const pathIndexShift = getPathIndexShift(rawSegment) + segments.length;
3689
+ snapshot = new ActivatedRouteSnapshot(segments, params, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component, route, getSourceSegmentGroup(rawSegment), pathIndexShift, getResolve(route),
3690
+ // NG_DEV_MODE is used to prevent the getCorrectedPathIndexShift function from affecting
3691
+ // production bundle size. This value is intended only to surface a warning to users
3692
+ // depending on `relativeLinkResolution: 'legacy'` in dev mode.
3693
+ (NG_DEV_MODE$2 ? getCorrectedPathIndexShift(rawSegment) + segments.length :
3694
+ pathIndexShift));
3636
3695
  }
3637
3696
  else {
3638
3697
  const result = match(rawSegment, route, segments);
@@ -3641,7 +3700,9 @@ class Recognizer {
3641
3700
  }
3642
3701
  consumedSegments = result.consumedSegments;
3643
3702
  remainingSegments = result.remainingSegments;
3644
- snapshot = new ActivatedRouteSnapshot(consumedSegments, result.parameters, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component, route, getSourceSegmentGroup(rawSegment), getPathIndexShift(rawSegment) + consumedSegments.length, getResolve(route));
3703
+ const pathIndexShift = getPathIndexShift(rawSegment) + consumedSegments.length;
3704
+ snapshot = new ActivatedRouteSnapshot(consumedSegments, result.parameters, Object.freeze({ ...this.urlTree.queryParams }), this.urlTree.fragment, getData(route), getOutlet(route), route.component, route, getSourceSegmentGroup(rawSegment), pathIndexShift, getResolve(route), (NG_DEV_MODE$2 ? getCorrectedPathIndexShift(rawSegment) + consumedSegments.length :
3705
+ pathIndexShift));
3645
3706
  }
3646
3707
  const childConfig = getChildConfig(route);
3647
3708
  const { segmentGroup, slicedSegments } = split(rawSegment, consumedSegments, remainingSegments,
@@ -3689,7 +3750,7 @@ function getChildConfig(route) {
3689
3750
  return route.children;
3690
3751
  }
3691
3752
  if (route.loadChildren) {
3692
- return route._loadedConfig.routes;
3753
+ return route._loadedRoutes;
3693
3754
  }
3694
3755
  return [];
3695
3756
  }
@@ -3751,10 +3812,19 @@ function getSourceSegmentGroup(segmentGroup) {
3751
3812
  }
3752
3813
  function getPathIndexShift(segmentGroup) {
3753
3814
  let s = segmentGroup;
3754
- let res = (s._segmentIndexShift ? s._segmentIndexShift : 0);
3815
+ let res = s._segmentIndexShift ?? 0;
3816
+ while (s._sourceSegment) {
3817
+ s = s._sourceSegment;
3818
+ res += s._segmentIndexShift ?? 0;
3819
+ }
3820
+ return res - 1;
3821
+ }
3822
+ function getCorrectedPathIndexShift(segmentGroup) {
3823
+ let s = segmentGroup;
3824
+ let res = s._segmentIndexShiftCorrected ?? s._segmentIndexShift ?? 0;
3755
3825
  while (s._sourceSegment) {
3756
3826
  s = s._sourceSegment;
3757
- res += (s._segmentIndexShift ? s._segmentIndexShift : 0);
3827
+ res += s._segmentIndexShiftCorrected ?? s._segmentIndexShift ?? 0;
3758
3828
  }
3759
3829
  return res - 1;
3760
3830
  }
@@ -3824,16 +3894,9 @@ function resolveNode(resolve, futureARS, futureRSS, moduleInjector) {
3824
3894
  }
3825
3895
  const data = {};
3826
3896
  return from(keys).pipe(mergeMap(key => getResolver(resolve[key], futureARS, futureRSS, moduleInjector)
3827
- .pipe(take(1), tap((value) => {
3897
+ .pipe(first(), tap((value) => {
3828
3898
  data[key] = value;
3829
- }))), takeLast(1), mergeMap(() => {
3830
- // Ensure all resolvers returned values, otherwise don't emit any "next" and just complete
3831
- // the chain which will cancel navigation
3832
- if (getDataKeys(data).length === keys.length) {
3833
- return of(data);
3834
- }
3835
- return EMPTY;
3836
- }));
3899
+ }))), takeLast(1), mapTo(data), catchError((e) => e instanceof EmptyError ? EMPTY : throwError(e)));
3837
3900
  }
3838
3901
  function getDataKeys(obj) {
3839
3902
  return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
@@ -3942,6 +4005,7 @@ class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
3942
4005
  * Use of this source code is governed by an MIT-style license that can be
3943
4006
  * found in the LICENSE file at https://angular.io/license
3944
4007
  */
4008
+ const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || !!ngDevMode;
3945
4009
  /**
3946
4010
  * The [DI token](guide/glossary/#di-token) for a router configuration.
3947
4011
  *
@@ -3954,15 +4018,17 @@ class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
3954
4018
  */
3955
4019
  const ROUTES = new InjectionToken('ROUTES');
3956
4020
  class RouterConfigLoader {
3957
- constructor(injector, compiler, onLoadStartListener, onLoadEndListener) {
4021
+ constructor(injector, compiler) {
3958
4022
  this.injector = injector;
3959
4023
  this.compiler = compiler;
3960
- this.onLoadStartListener = onLoadStartListener;
3961
- this.onLoadEndListener = onLoadEndListener;
4024
+ this.routeLoaders = new WeakMap();
3962
4025
  }
3963
4026
  load(parentInjector, route) {
3964
- if (route._loader$) {
3965
- return route._loader$;
4027
+ if (this.routeLoaders.get(route)) {
4028
+ return this.routeLoaders.get(route);
4029
+ }
4030
+ else if (route._loadedRoutes) {
4031
+ return of({ routes: route._loadedRoutes, injector: route._loadedInjector });
3966
4032
  }
3967
4033
  if (this.onLoadStartListener) {
3968
4034
  this.onLoadStartListener(route);
@@ -3972,21 +4038,24 @@ class RouterConfigLoader {
3972
4038
  if (this.onLoadEndListener) {
3973
4039
  this.onLoadEndListener(route);
3974
4040
  }
3975
- const module = factory.create(parentInjector);
4041
+ const injector = factory.create(parentInjector).injector;
4042
+ const routes =
3976
4043
  // When loading a module that doesn't provide `RouterModule.forChild()` preloader
3977
4044
  // will get stuck in an infinite loop. The child module's Injector will look to
3978
4045
  // its parent `Injector` when it doesn't find any ROUTES so it will return routes
3979
4046
  // for it's parent module instead.
3980
- return new LoadedRouterConfig(flatten(module.injector.get(ROUTES, undefined, InjectFlags.Self | InjectFlags.Optional))
3981
- .map(standardizeConfig), module);
3982
- }), catchError((err) => {
3983
- route._loader$ = undefined;
3984
- throw err;
4047
+ flatten(injector.get(ROUTES, [], InjectFlags.Self | InjectFlags.Optional))
4048
+ .map(standardizeConfig);
4049
+ NG_DEV_MODE$1 && validateConfig(routes);
4050
+ return { routes, injector };
4051
+ }), finalize(() => {
4052
+ this.routeLoaders.delete(route);
3985
4053
  }));
3986
4054
  // Use custom ConnectableObservable as share in runners pipe increasing the bundle size too much
3987
- route._loader$ = new ConnectableObservable(loadRunner, () => new Subject())
4055
+ const loader = new ConnectableObservable(loadRunner, () => new Subject())
3988
4056
  .pipe(refCount());
3989
- return route._loader$;
4057
+ this.routeLoaders.set(route, loader);
4058
+ return loader;
3990
4059
  }
3991
4060
  loadModuleFactory(loadChildren) {
3992
4061
  return wrapIntoObservable(loadChildren()).pipe(mergeMap((t) => {
@@ -3999,6 +4068,11 @@ class RouterConfigLoader {
3999
4068
  }));
4000
4069
  }
4001
4070
  }
4071
+ RouterConfigLoader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterConfigLoader, deps: [{ token: i0.Injector }, { token: i0.Compiler }], target: i0.ɵɵFactoryTarget.Injectable });
4072
+ RouterConfigLoader.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterConfigLoader });
4073
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterConfigLoader, decorators: [{
4074
+ type: Injectable
4075
+ }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.Compiler }]; } });
4002
4076
 
4003
4077
  /**
4004
4078
  * @license
@@ -4038,6 +4112,7 @@ class DefaultUrlHandlingStrategy {
4038
4112
  * Use of this source code is governed by an MIT-style license that can be
4039
4113
  * found in the LICENSE file at https://angular.io/license
4040
4114
  */
4115
+ const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
4041
4116
  function defaultErrorHandler(error) {
4042
4117
  throw error;
4043
4118
  }
@@ -4209,6 +4284,9 @@ class Router {
4209
4284
  this.canceledNavigationResolution = 'replace';
4210
4285
  const onLoadStart = (r) => this.triggerEvent(new RouteConfigLoadStart(r));
4211
4286
  const onLoadEnd = (r) => this.triggerEvent(new RouteConfigLoadEnd(r));
4287
+ this.configLoader = injector.get(RouterConfigLoader);
4288
+ this.configLoader.onLoadEndListener = onLoadEnd;
4289
+ this.configLoader.onLoadStartListener = onLoadStart;
4212
4290
  this.ngModule = injector.get(NgModuleRef);
4213
4291
  this.console = injector.get(ɵConsole);
4214
4292
  const ngZone = injector.get(NgZone);
@@ -4217,7 +4295,6 @@ class Router {
4217
4295
  this.currentUrlTree = createEmptyUrlTree();
4218
4296
  this.rawUrlTree = this.currentUrlTree;
4219
4297
  this.browserUrlTree = this.currentUrlTree;
4220
- this.configLoader = new RouterConfigLoader(injector, compiler, onLoadStart, onLoadEnd);
4221
4298
  this.routerState = createEmptyState(this.currentUrlTree, this.rootComponentType);
4222
4299
  this.transitions = new BehaviorSubject({
4223
4300
  id: 0,
@@ -4630,7 +4707,7 @@ class Router {
4630
4707
  * ```
4631
4708
  */
4632
4709
  resetConfig(config) {
4633
- validateConfig(config);
4710
+ NG_DEV_MODE && validateConfig(config);
4634
4711
  this.config = config.map(standardizeConfig);
4635
4712
  this.navigated = false;
4636
4713
  this.lastSuccessfulId = -1;
@@ -4985,9 +5062,9 @@ class Router {
4985
5062
  return { navigationId };
4986
5063
  }
4987
5064
  }
4988
- Router.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: Router, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
4989
- Router.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: Router });
4990
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: Router, decorators: [{
5065
+ Router.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: Router, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
5066
+ Router.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: Router });
5067
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: Router, decorators: [{
4991
5068
  type: Injectable
4992
5069
  }], ctorParameters: function () { return [{ type: i0.Type }, { type: UrlSerializer }, { type: ChildrenOutletContexts }, { type: i3.Location }, { type: i0.Injector }, { type: i0.Compiler }, { type: undefined }]; } });
4993
5070
  function validateCommands(commands) {
@@ -5186,9 +5263,9 @@ class RouterLink {
5186
5263
  });
5187
5264
  }
5188
5265
  }
5189
- RouterLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterLink, deps: [{ token: Router }, { token: ActivatedRoute }, { token: 'tabindex', attribute: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
5190
- RouterLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.11", type: RouterLink, selector: ":not(a):not(area)[routerLink]", inputs: { queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", state: "state", relativeTo: "relativeTo", routerLink: "routerLink" }, host: { listeners: { "click": "onClick()" } }, usesOnChanges: true, ngImport: i0 });
5191
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterLink, decorators: [{
5266
+ RouterLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterLink, deps: [{ token: Router }, { token: ActivatedRoute }, { token: 'tabindex', attribute: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
5267
+ RouterLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.14", type: RouterLink, selector: ":not(a):not(area)[routerLink]", inputs: { queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", state: "state", relativeTo: "relativeTo", routerLink: "routerLink" }, host: { listeners: { "click": "onClick()" } }, usesOnChanges: true, ngImport: i0 });
5268
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterLink, decorators: [{
5192
5269
  type: Directive,
5193
5270
  args: [{ selector: ':not(a):not(area)[routerLink]' }]
5194
5271
  }], ctorParameters: function () { return [{ type: Router }, { type: ActivatedRoute }, { type: undefined, decorators: [{
@@ -5305,9 +5382,9 @@ class RouterLinkWithHref {
5305
5382
  });
5306
5383
  }
5307
5384
  }
5308
- RouterLinkWithHref.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterLinkWithHref, deps: [{ token: Router }, { token: ActivatedRoute }, { token: i3.LocationStrategy }], target: i0.ɵɵFactoryTarget.Directive });
5309
- RouterLinkWithHref.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.11", type: RouterLinkWithHref, selector: "a[routerLink],area[routerLink]", inputs: { target: "target", queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", state: "state", relativeTo: "relativeTo", routerLink: "routerLink" }, host: { listeners: { "click": "onClick($event.button,$event.ctrlKey,$event.shiftKey,$event.altKey,$event.metaKey)" }, properties: { "attr.target": "this.target", "attr.href": "this.href" } }, usesOnChanges: true, ngImport: i0 });
5310
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterLinkWithHref, decorators: [{
5385
+ RouterLinkWithHref.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterLinkWithHref, deps: [{ token: Router }, { token: ActivatedRoute }, { token: i3.LocationStrategy }], target: i0.ɵɵFactoryTarget.Directive });
5386
+ RouterLinkWithHref.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.14", type: RouterLinkWithHref, selector: "a[routerLink],area[routerLink]", inputs: { target: "target", queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", preserveFragment: "preserveFragment", skipLocationChange: "skipLocationChange", replaceUrl: "replaceUrl", state: "state", relativeTo: "relativeTo", routerLink: "routerLink" }, host: { listeners: { "click": "onClick($event.button,$event.ctrlKey,$event.shiftKey,$event.altKey,$event.metaKey)" }, properties: { "attr.target": "this.target", "attr.href": "this.href" } }, usesOnChanges: true, ngImport: i0 });
5387
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterLinkWithHref, decorators: [{
5311
5388
  type: Directive,
5312
5389
  args: [{ selector: 'a[routerLink],area[routerLink]' }]
5313
5390
  }], ctorParameters: function () { return [{ type: Router }, { type: ActivatedRoute }, { type: i3.LocationStrategy }]; }, propDecorators: { target: [{
@@ -5516,9 +5593,9 @@ class RouterLinkActive {
5516
5593
  this.links.some(isActiveCheckFn) || this.linksWithHrefs.some(isActiveCheckFn);
5517
5594
  }
5518
5595
  }
5519
- RouterLinkActive.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterLinkActive, deps: [{ token: Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: RouterLink, optional: true }, { token: RouterLinkWithHref, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
5520
- RouterLinkActive.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.11", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: { routerLinkActiveOptions: "routerLinkActiveOptions", routerLinkActive: "routerLinkActive" }, outputs: { isActiveChange: "isActiveChange" }, queries: [{ propertyName: "links", predicate: RouterLink, descendants: true }, { propertyName: "linksWithHrefs", predicate: RouterLinkWithHref, descendants: true }], exportAs: ["routerLinkActive"], usesOnChanges: true, ngImport: i0 });
5521
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterLinkActive, decorators: [{
5596
+ RouterLinkActive.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterLinkActive, deps: [{ token: Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: RouterLink, optional: true }, { token: RouterLinkWithHref, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
5597
+ RouterLinkActive.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.14", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: { routerLinkActiveOptions: "routerLinkActiveOptions", routerLinkActive: "routerLinkActive" }, outputs: { isActiveChange: "isActiveChange" }, queries: [{ propertyName: "links", predicate: RouterLink, descendants: true }, { propertyName: "linksWithHrefs", predicate: RouterLinkWithHref, descendants: true }], exportAs: ["routerLinkActive"], usesOnChanges: true, ngImport: i0 });
5598
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterLinkActive, decorators: [{
5522
5599
  type: Directive,
5523
5600
  args: [{
5524
5601
  selector: '[routerLinkActive]',
@@ -5619,9 +5696,9 @@ class DefaultTitleStrategy extends TitleStrategy {
5619
5696
  }
5620
5697
  }
5621
5698
  }
5622
- DefaultTitleStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: DefaultTitleStrategy, deps: [{ token: i1.Title }], target: i0.ɵɵFactoryTarget.Injectable });
5623
- DefaultTitleStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: DefaultTitleStrategy, providedIn: 'root' });
5624
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: DefaultTitleStrategy, decorators: [{
5699
+ DefaultTitleStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: DefaultTitleStrategy, deps: [{ token: i1.Title }], target: i0.ɵɵFactoryTarget.Injectable });
5700
+ DefaultTitleStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: DefaultTitleStrategy, providedIn: 'root' });
5701
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: DefaultTitleStrategy, decorators: [{
5625
5702
  type: Injectable,
5626
5703
  args: [{ providedIn: 'root' }]
5627
5704
  }], ctorParameters: function () { return [{ type: i1.Title }]; } });
@@ -5685,13 +5762,11 @@ class NoPreloading {
5685
5762
  * @publicApi
5686
5763
  */
5687
5764
  class RouterPreloader {
5688
- constructor(router, compiler, injector, preloadingStrategy) {
5765
+ constructor(router, compiler, injector, preloadingStrategy, loader) {
5689
5766
  this.router = router;
5690
5767
  this.injector = injector;
5691
5768
  this.preloadingStrategy = preloadingStrategy;
5692
- const onStartLoad = (r) => router.triggerEvent(new RouteConfigLoadStart(r));
5693
- const onEndLoad = (r) => router.triggerEvent(new RouteConfigLoadEnd(r));
5694
- this.loader = new RouterConfigLoader(injector, compiler, onStartLoad, onEndLoad);
5769
+ this.loader = loader;
5695
5770
  }
5696
5771
  setUpPreloading() {
5697
5772
  this.subscription =
@@ -5700,8 +5775,7 @@ class RouterPreloader {
5700
5775
  .subscribe(() => { });
5701
5776
  }
5702
5777
  preload() {
5703
- const ngModule = this.injector.get(NgModuleRef);
5704
- return this.processRoutes(ngModule, this.router.config);
5778
+ return this.processRoutes(this.injector, this.router.config);
5705
5779
  }
5706
5780
  /** @nodoc */
5707
5781
  ngOnDestroy() {
@@ -5709,41 +5783,50 @@ class RouterPreloader {
5709
5783
  this.subscription.unsubscribe();
5710
5784
  }
5711
5785
  }
5712
- processRoutes(ngModule, routes) {
5786
+ processRoutes(injector, routes) {
5713
5787
  const res = [];
5714
5788
  for (const route of routes) {
5789
+ if (route.providers && !route._injector) {
5790
+ route._injector =
5791
+ createEnvironmentInjector(route.providers, injector, `Route: ${route.path}`);
5792
+ }
5793
+ const injectorForCurrentRoute = route._injector ?? injector;
5794
+ const injectorForChildren = route._loadedInjector ?? injectorForCurrentRoute;
5715
5795
  // we already have the config loaded, just recurse
5716
- if (route.loadChildren && !route.canLoad && route._loadedConfig) {
5717
- const childConfig = route._loadedConfig;
5718
- res.push(this.processRoutes(childConfig.module, childConfig.routes));
5796
+ if (route.loadChildren && !route.canLoad && route._loadedRoutes) {
5797
+ res.push(this.processRoutes(injectorForChildren, route._loadedRoutes));
5719
5798
  // no config loaded, fetch the config
5720
5799
  }
5721
5800
  else if (route.loadChildren && !route.canLoad) {
5722
- res.push(this.preloadConfig(ngModule, route));
5801
+ res.push(this.preloadConfig(injectorForCurrentRoute, route));
5723
5802
  // recurse into children
5724
5803
  }
5725
5804
  else if (route.children) {
5726
- res.push(this.processRoutes(ngModule, route.children));
5805
+ res.push(this.processRoutes(injectorForChildren, route.children));
5727
5806
  }
5728
5807
  }
5729
5808
  return from(res).pipe(mergeAll(), map((_) => void 0));
5730
5809
  }
5731
- preloadConfig(ngModule, route) {
5810
+ preloadConfig(injector, route) {
5732
5811
  return this.preloadingStrategy.preload(route, () => {
5733
- const loaded$ = route._loadedConfig ? of(route._loadedConfig) :
5734
- this.loader.load(ngModule.injector, route);
5812
+ const loaded$ = route._loadedRoutes ?
5813
+ of({ routes: route._loadedRoutes, injector: route._loadedInjector }) :
5814
+ this.loader.load(injector, route);
5735
5815
  return loaded$.pipe(mergeMap((config) => {
5736
- route._loadedConfig = config;
5737
- return this.processRoutes(config.module, config.routes);
5816
+ route._loadedRoutes = config.routes;
5817
+ route._loadedInjector = config.injector;
5818
+ // If the loaded config was a module, use that as the module/module injector going forward.
5819
+ // Otherwise, continue using the current module/module injector.
5820
+ return this.processRoutes(config.injector ?? injector, config.routes);
5738
5821
  }));
5739
5822
  });
5740
5823
  }
5741
5824
  }
5742
- RouterPreloader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterPreloader, deps: [{ token: Router }, { token: i0.Compiler }, { token: i0.Injector }, { token: PreloadingStrategy }], target: i0.ɵɵFactoryTarget.Injectable });
5743
- RouterPreloader.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterPreloader });
5744
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterPreloader, decorators: [{
5825
+ RouterPreloader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterPreloader, deps: [{ token: Router }, { token: i0.Compiler }, { token: i0.EnvironmentInjector }, { token: PreloadingStrategy }, { token: RouterConfigLoader }], target: i0.ɵɵFactoryTarget.Injectable });
5826
+ RouterPreloader.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterPreloader });
5827
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterPreloader, decorators: [{
5745
5828
  type: Injectable
5746
- }], ctorParameters: function () { return [{ type: Router }, { type: i0.Compiler }, { type: i0.Injector }, { type: PreloadingStrategy }]; } });
5829
+ }], ctorParameters: function () { return [{ type: Router }, { type: i0.Compiler }, { type: i0.EnvironmentInjector }, { type: PreloadingStrategy }, { type: RouterConfigLoader }]; } });
5747
5830
 
5748
5831
  /**
5749
5832
  * @license
@@ -5827,9 +5910,9 @@ class RouterScroller {
5827
5910
  }
5828
5911
  }
5829
5912
  }
5830
- RouterScroller.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterScroller, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
5831
- RouterScroller.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterScroller });
5832
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterScroller, decorators: [{
5913
+ RouterScroller.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterScroller, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable });
5914
+ RouterScroller.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterScroller });
5915
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterScroller, decorators: [{
5833
5916
  type: Injectable
5834
5917
  }], ctorParameters: function () { return [{ type: Router }, { type: i3.ViewportScroller }, { type: undefined }]; } });
5835
5918
 
@@ -5872,6 +5955,7 @@ const ROUTER_PROVIDERS = [
5872
5955
  NoPreloading,
5873
5956
  PreloadAllModules,
5874
5957
  { provide: ROUTER_CONFIGURATION, useValue: { enableTracing: false } },
5958
+ RouterConfigLoader,
5875
5959
  ];
5876
5960
  function routerNgProbeToken() {
5877
5961
  return new NgProbeToken('Router', Router);
@@ -5970,10 +6054,10 @@ class RouterModule {
5970
6054
  return { ngModule: RouterModule, providers: [provideRoutes(routes)] };
5971
6055
  }
5972
6056
  }
5973
- RouterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterModule, deps: [{ token: ROUTER_FORROOT_GUARD, optional: true }, { token: Router, optional: true }], target: i0.ɵɵFactoryTarget.NgModule });
5974
- RouterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterModule, declarations: [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive, ɵEmptyOutletComponent], exports: [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive, ɵEmptyOutletComponent] });
5975
- RouterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterModule });
5976
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterModule, decorators: [{
6057
+ RouterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterModule, deps: [{ token: ROUTER_FORROOT_GUARD, optional: true }, { token: Router, optional: true }], target: i0.ɵɵFactoryTarget.NgModule });
6058
+ RouterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterModule, declarations: [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive, ɵEmptyOutletComponent], exports: [RouterOutlet, RouterLink, RouterLinkWithHref, RouterLinkActive, ɵEmptyOutletComponent] });
6059
+ RouterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterModule });
6060
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterModule, decorators: [{
5977
6061
  type: NgModule,
5978
6062
  args: [{
5979
6063
  declarations: ROUTER_DIRECTIVES,
@@ -6152,9 +6236,9 @@ class RouterInitializer {
6152
6236
  this.destroyed = true;
6153
6237
  }
6154
6238
  }
6155
- RouterInitializer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterInitializer, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
6156
- RouterInitializer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterInitializer });
6157
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.11", ngImport: i0, type: RouterInitializer, decorators: [{
6239
+ RouterInitializer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterInitializer, deps: [{ token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
6240
+ RouterInitializer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterInitializer });
6241
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.14", ngImport: i0, type: RouterInitializer, decorators: [{
6158
6242
  type: Injectable
6159
6243
  }], ctorParameters: function () { return [{ type: i0.Injector }]; } });
6160
6244
  function getAppInitializer(r) {
@@ -6194,7 +6278,7 @@ function provideRouterInitializer() {
6194
6278
  /**
6195
6279
  * @publicApi
6196
6280
  */
6197
- const VERSION = new Version('14.0.0-next.11');
6281
+ const VERSION = new Version('14.0.0-next.14');
6198
6282
 
6199
6283
  /**
6200
6284
  * @license