@angular/router 14.0.0-next.13 → 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.
- package/esm2020/src/apply_redirects.mjs +56 -46
- package/esm2020/src/components/empty_outlet.mjs +3 -3
- package/esm2020/src/directives/router_link.mjs +6 -6
- package/esm2020/src/directives/router_link_active.mjs +3 -3
- package/esm2020/src/directives/router_outlet.mjs +24 -15
- package/esm2020/src/models.mjs +2 -7
- package/esm2020/src/operators/activate_routes.mjs +7 -14
- package/esm2020/src/operators/apply_redirects.mjs +3 -3
- package/esm2020/src/operators/resolve_data.mjs +5 -12
- package/esm2020/src/page_title_strategy.mjs +3 -3
- package/esm2020/src/recognize.mjs +2 -2
- package/esm2020/src/router.mjs +9 -6
- package/esm2020/src/router_config_loader.mjs +29 -18
- package/esm2020/src/router_module.mjs +10 -9
- package/esm2020/src/router_outlet_context.mjs +6 -1
- package/esm2020/src/router_preloader.mjs +31 -24
- package/esm2020/src/router_scroller.mjs +3 -3
- package/esm2020/src/router_state.mjs +1 -2
- package/esm2020/src/utils/config.mjs +44 -1
- package/esm2020/src/utils/preactivation.mjs +5 -14
- package/esm2020/src/version.mjs +1 -1
- package/esm2020/testing/src/router_testing_module.mjs +4 -4
- package/fesm2015/router.mjs +667 -613
- package/fesm2015/router.mjs.map +1 -1
- package/fesm2015/testing.mjs +5 -5
- package/fesm2015/upgrade.mjs +1 -1
- package/fesm2020/router.mjs +661 -613
- package/fesm2020/router.mjs.map +1 -1
- package/fesm2020/testing.mjs +5 -5
- package/fesm2020/upgrade.mjs +1 -1
- package/package.json +4 -4
- package/router.d.ts +53 -13
- package/testing/testing.d.ts +1 -1
- package/upgrade/upgrade.d.ts +1 -1
package/fesm2020/router.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v14.0.0-next.
|
|
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,
|
|
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,
|
|
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;
|
|
@@ -2020,181 +2019,76 @@ function compare(path, params, segment) {
|
|
|
2020
2019
|
* Use of this source code is governed by an MIT-style license that can be
|
|
2021
2020
|
* found in the LICENSE file at https://angular.io/license
|
|
2022
2021
|
*/
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
class
|
|
2029
|
-
constructor(
|
|
2030
|
-
this.
|
|
2031
|
-
this.
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
this.
|
|
2039
|
-
|
|
2040
|
-
this.activateChildRoutes(futureRoot, currRoot, parentContexts);
|
|
2041
|
-
}
|
|
2042
|
-
// De-activate the child route that are not re-used for the future state
|
|
2043
|
-
deactivateChildRoutes(futureNode, currNode, contexts) {
|
|
2044
|
-
const children = nodeChildrenAsMap(currNode);
|
|
2045
|
-
// Recurse on the routes active in the future state to de-activate deeper children
|
|
2046
|
-
futureNode.children.forEach(futureChild => {
|
|
2047
|
-
const childOutletName = futureChild.value.outlet;
|
|
2048
|
-
this.deactivateRoutes(futureChild, children[childOutletName], contexts);
|
|
2049
|
-
delete children[childOutletName];
|
|
2050
|
-
});
|
|
2051
|
-
// De-activate the routes that will not be re-used
|
|
2052
|
-
forEach(children, (v, childName) => {
|
|
2053
|
-
this.deactivateRouteAndItsChildren(v, contexts);
|
|
2054
|
-
});
|
|
2055
|
-
}
|
|
2056
|
-
deactivateRoutes(futureNode, currNode, parentContext) {
|
|
2057
|
-
const future = futureNode.value;
|
|
2058
|
-
const curr = currNode ? currNode.value : null;
|
|
2059
|
-
if (future === curr) {
|
|
2060
|
-
// Reusing the node, check to see if the children need to be de-activated
|
|
2061
|
-
if (future.component) {
|
|
2062
|
-
// If we have a normal route, we need to go through an outlet.
|
|
2063
|
-
const context = parentContext.getContext(future.outlet);
|
|
2064
|
-
if (context) {
|
|
2065
|
-
this.deactivateChildRoutes(futureNode, currNode, context.children);
|
|
2066
|
-
}
|
|
2067
|
-
}
|
|
2068
|
-
else {
|
|
2069
|
-
// if we have a componentless route, we recurse but keep the same outlet map.
|
|
2070
|
-
this.deactivateChildRoutes(futureNode, currNode, parentContext);
|
|
2071
|
-
}
|
|
2072
|
-
}
|
|
2073
|
-
else {
|
|
2074
|
-
if (curr) {
|
|
2075
|
-
// Deactivate the current route which will not be re-used
|
|
2076
|
-
this.deactivateRouteAndItsChildren(currNode, parentContext);
|
|
2077
|
-
}
|
|
2078
|
-
}
|
|
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;
|
|
2079
2039
|
}
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
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();
|
|
2089
2050
|
}
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
const
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
|
|
2096
|
-
}
|
|
2097
|
-
if (context && context.outlet) {
|
|
2098
|
-
const componentRef = context.outlet.detach();
|
|
2099
|
-
const contexts = context.children.onOutletDeactivated();
|
|
2100
|
-
this.routeReuseStrategy.store(route.value.snapshot, { componentRef, route, contexts });
|
|
2101
|
-
}
|
|
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);
|
|
2102
2056
|
}
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
if (context && context.outlet) {
|
|
2113
|
-
// Destroy the component
|
|
2114
|
-
context.outlet.deactivate();
|
|
2115
|
-
// Destroy the contexts for all the outlets that were in the component
|
|
2116
|
-
context.children.onOutletDeactivated();
|
|
2117
|
-
// Clear the information about the attached component on the context but keep the reference to
|
|
2118
|
-
// 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;
|
|
2119
2066
|
context.attachRef = null;
|
|
2120
|
-
context.resolver = null;
|
|
2121
|
-
context.route = null;
|
|
2122
2067
|
}
|
|
2123
2068
|
}
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
}
|
|
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;
|
|
2133
2077
|
}
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
if (
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
const context = parentContexts.getOrCreateContext(future.outlet);
|
|
2143
|
-
this.activateChildRoutes(futureNode, currNode, context.children);
|
|
2144
|
-
}
|
|
2145
|
-
else {
|
|
2146
|
-
// if we have a componentless route, we recurse but keep the same outlet map.
|
|
2147
|
-
this.activateChildRoutes(futureNode, currNode, parentContexts);
|
|
2148
|
-
}
|
|
2149
|
-
}
|
|
2150
|
-
else {
|
|
2151
|
-
if (future.component) {
|
|
2152
|
-
// if we have a normal route, we need to place the component into the outlet and recurse.
|
|
2153
|
-
const context = parentContexts.getOrCreateContext(future.outlet);
|
|
2154
|
-
if (this.routeReuseStrategy.shouldAttach(future.snapshot)) {
|
|
2155
|
-
const stored = this.routeReuseStrategy.retrieve(future.snapshot);
|
|
2156
|
-
this.routeReuseStrategy.store(future.snapshot, null);
|
|
2157
|
-
context.children.onOutletReAttached(stored.contexts);
|
|
2158
|
-
context.attachRef = stored.componentRef;
|
|
2159
|
-
context.route = stored.route.value;
|
|
2160
|
-
if (context.outlet) {
|
|
2161
|
-
// Attach right away when the outlet has already been instantiated
|
|
2162
|
-
// Otherwise attach from `RouterOutlet.ngOnInit` when it is instantiated
|
|
2163
|
-
context.outlet.attach(stored.componentRef, stored.route.value);
|
|
2164
|
-
}
|
|
2165
|
-
advanceActivatedRoute(stored.route.value);
|
|
2166
|
-
this.activateChildRoutes(futureNode, null, context.children);
|
|
2167
|
-
}
|
|
2168
|
-
else {
|
|
2169
|
-
const config = parentLoadedConfig(future.snapshot);
|
|
2170
|
-
const cmpFactoryResolver = config ? config.module.componentFactoryResolver : null;
|
|
2171
|
-
context.attachRef = null;
|
|
2172
|
-
context.route = future;
|
|
2173
|
-
context.resolver = cmpFactoryResolver;
|
|
2174
|
-
if (context.outlet) {
|
|
2175
|
-
// Activate the outlet when it has already been instantiated
|
|
2176
|
-
// Otherwise it will get activated from its `ngOnInit` when instantiated
|
|
2177
|
-
context.outlet.activateWith(future, cmpFactoryResolver);
|
|
2178
|
-
}
|
|
2179
|
-
this.activateChildRoutes(futureNode, null, context.children);
|
|
2180
|
-
}
|
|
2181
|
-
}
|
|
2182
|
-
else {
|
|
2183
|
-
// if we have a componentless route, we recurse but keep the same outlet map.
|
|
2184
|
-
this.activateChildRoutes(futureNode, null, parentContexts);
|
|
2185
|
-
}
|
|
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);
|
|
2186
2086
|
}
|
|
2087
|
+
return context;
|
|
2187
2088
|
}
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
for (let s = snapshot.parent; s; s = s.parent) {
|
|
2191
|
-
const route = s.routeConfig;
|
|
2192
|
-
if (route && route._loadedConfig)
|
|
2193
|
-
return route._loadedConfig;
|
|
2194
|
-
if (route && route.component)
|
|
2195
|
-
return null;
|
|
2089
|
+
getContext(childName) {
|
|
2090
|
+
return this.contexts.get(childName) || null;
|
|
2196
2091
|
}
|
|
2197
|
-
return null;
|
|
2198
2092
|
}
|
|
2199
2093
|
|
|
2200
2094
|
/**
|
|
@@ -2204,182 +2098,13 @@ function parentLoadedConfig(snapshot) {
|
|
|
2204
2098
|
* Use of this source code is governed by an MIT-style license that can be
|
|
2205
2099
|
* found in the LICENSE file at https://angular.io/license
|
|
2206
2100
|
*/
|
|
2207
|
-
class LoadedRouterConfig {
|
|
2208
|
-
constructor(routes, module) {
|
|
2209
|
-
this.routes = routes;
|
|
2210
|
-
this.module = module;
|
|
2211
|
-
}
|
|
2212
|
-
}
|
|
2213
|
-
|
|
2214
2101
|
/**
|
|
2215
|
-
* @
|
|
2216
|
-
* Copyright Google LLC All Rights Reserved.
|
|
2102
|
+
* @description
|
|
2217
2103
|
*
|
|
2218
|
-
*
|
|
2219
|
-
* found in the LICENSE file at https://angular.io/license
|
|
2220
|
-
*/
|
|
2221
|
-
/**
|
|
2222
|
-
* 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.
|
|
2223
2105
|
*
|
|
2224
|
-
*
|
|
2225
|
-
*
|
|
2226
|
-
* }
|
|
2227
|
-
*
|
|
2228
|
-
* if (isFunction<product>(fn)) {
|
|
2229
|
-
* return fn(1, 2);
|
|
2230
|
-
* } else {
|
|
2231
|
-
* throw "Must provide the `product` function";
|
|
2232
|
-
* }
|
|
2233
|
-
*/
|
|
2234
|
-
function isFunction(v) {
|
|
2235
|
-
return typeof v === 'function';
|
|
2236
|
-
}
|
|
2237
|
-
function isBoolean(v) {
|
|
2238
|
-
return typeof v === 'boolean';
|
|
2239
|
-
}
|
|
2240
|
-
function isUrlTree(v) {
|
|
2241
|
-
return v instanceof UrlTree;
|
|
2242
|
-
}
|
|
2243
|
-
function isCanLoad(guard) {
|
|
2244
|
-
return guard && isFunction(guard.canLoad);
|
|
2245
|
-
}
|
|
2246
|
-
function isCanActivate(guard) {
|
|
2247
|
-
return guard && isFunction(guard.canActivate);
|
|
2248
|
-
}
|
|
2249
|
-
function isCanActivateChild(guard) {
|
|
2250
|
-
return guard && isFunction(guard.canActivateChild);
|
|
2251
|
-
}
|
|
2252
|
-
function isCanDeactivate(guard) {
|
|
2253
|
-
return guard && isFunction(guard.canDeactivate);
|
|
2254
|
-
}
|
|
2255
|
-
|
|
2256
|
-
/**
|
|
2257
|
-
* @license
|
|
2258
|
-
* Copyright Google LLC All Rights Reserved.
|
|
2259
|
-
*
|
|
2260
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
2261
|
-
* found in the LICENSE file at https://angular.io/license
|
|
2262
|
-
*/
|
|
2263
|
-
const INITIAL_VALUE = Symbol('INITIAL_VALUE');
|
|
2264
|
-
function prioritizedGuardValue() {
|
|
2265
|
-
return switchMap(obs => {
|
|
2266
|
-
return combineLatest(obs.map(o => o.pipe(take(1), startWith(INITIAL_VALUE))))
|
|
2267
|
-
.pipe(scan((acc, list) => {
|
|
2268
|
-
let isPending = false;
|
|
2269
|
-
return list.reduce((innerAcc, val, i) => {
|
|
2270
|
-
if (innerAcc !== INITIAL_VALUE)
|
|
2271
|
-
return innerAcc;
|
|
2272
|
-
// Toggle pending flag if any values haven't been set yet
|
|
2273
|
-
if (val === INITIAL_VALUE)
|
|
2274
|
-
isPending = true;
|
|
2275
|
-
// Any other return values are only valid if we haven't yet hit a pending
|
|
2276
|
-
// call. This guarantees that in the case of a guard at the bottom of the
|
|
2277
|
-
// tree that returns a redirect, we will wait for the higher priority
|
|
2278
|
-
// guard at the top to finish before performing the redirect.
|
|
2279
|
-
if (!isPending) {
|
|
2280
|
-
// Early return when we hit a `false` value as that should always
|
|
2281
|
-
// cancel navigation
|
|
2282
|
-
if (val === false)
|
|
2283
|
-
return val;
|
|
2284
|
-
if (i === list.length - 1 || isUrlTree(val)) {
|
|
2285
|
-
return val;
|
|
2286
|
-
}
|
|
2287
|
-
}
|
|
2288
|
-
return innerAcc;
|
|
2289
|
-
}, acc);
|
|
2290
|
-
}, INITIAL_VALUE), filter(item => item !== INITIAL_VALUE), map(item => isUrlTree(item) ? item : item === true), //
|
|
2291
|
-
take(1));
|
|
2292
|
-
});
|
|
2293
|
-
}
|
|
2294
|
-
|
|
2295
|
-
/**
|
|
2296
|
-
* @license
|
|
2297
|
-
* Copyright Google LLC All Rights Reserved.
|
|
2298
|
-
*
|
|
2299
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
2300
|
-
* found in the LICENSE file at https://angular.io/license
|
|
2301
|
-
*/
|
|
2302
|
-
/**
|
|
2303
|
-
* Store contextual information about a `RouterOutlet`
|
|
2304
|
-
*
|
|
2305
|
-
* @publicApi
|
|
2306
|
-
*/
|
|
2307
|
-
class OutletContext {
|
|
2308
|
-
constructor() {
|
|
2309
|
-
this.outlet = null;
|
|
2310
|
-
this.route = null;
|
|
2311
|
-
this.resolver = null;
|
|
2312
|
-
this.children = new ChildrenOutletContexts();
|
|
2313
|
-
this.attachRef = null;
|
|
2314
|
-
}
|
|
2315
|
-
}
|
|
2316
|
-
/**
|
|
2317
|
-
* Store contextual information about the children (= nested) `RouterOutlet`
|
|
2318
|
-
*
|
|
2319
|
-
* @publicApi
|
|
2320
|
-
*/
|
|
2321
|
-
class ChildrenOutletContexts {
|
|
2322
|
-
constructor() {
|
|
2323
|
-
// contexts for child outlets, by name.
|
|
2324
|
-
this.contexts = new Map();
|
|
2325
|
-
}
|
|
2326
|
-
/** Called when a `RouterOutlet` directive is instantiated */
|
|
2327
|
-
onChildOutletCreated(childName, outlet) {
|
|
2328
|
-
const context = this.getOrCreateContext(childName);
|
|
2329
|
-
context.outlet = outlet;
|
|
2330
|
-
this.contexts.set(childName, context);
|
|
2331
|
-
}
|
|
2332
|
-
/**
|
|
2333
|
-
* Called when a `RouterOutlet` directive is destroyed.
|
|
2334
|
-
* We need to keep the context as the outlet could be destroyed inside a NgIf and might be
|
|
2335
|
-
* re-created later.
|
|
2336
|
-
*/
|
|
2337
|
-
onChildOutletDestroyed(childName) {
|
|
2338
|
-
const context = this.getContext(childName);
|
|
2339
|
-
if (context) {
|
|
2340
|
-
context.outlet = null;
|
|
2341
|
-
context.attachRef = null;
|
|
2342
|
-
}
|
|
2343
|
-
}
|
|
2344
|
-
/**
|
|
2345
|
-
* Called when the corresponding route is deactivated during navigation.
|
|
2346
|
-
* Because the component get destroyed, all children outlet are destroyed.
|
|
2347
|
-
*/
|
|
2348
|
-
onOutletDeactivated() {
|
|
2349
|
-
const contexts = this.contexts;
|
|
2350
|
-
this.contexts = new Map();
|
|
2351
|
-
return contexts;
|
|
2352
|
-
}
|
|
2353
|
-
onOutletReAttached(contexts) {
|
|
2354
|
-
this.contexts = contexts;
|
|
2355
|
-
}
|
|
2356
|
-
getOrCreateContext(childName) {
|
|
2357
|
-
let context = this.getContext(childName);
|
|
2358
|
-
if (!context) {
|
|
2359
|
-
context = new OutletContext();
|
|
2360
|
-
this.contexts.set(childName, context);
|
|
2361
|
-
}
|
|
2362
|
-
return context;
|
|
2363
|
-
}
|
|
2364
|
-
getContext(childName) {
|
|
2365
|
-
return this.contexts.get(childName) || null;
|
|
2366
|
-
}
|
|
2367
|
-
}
|
|
2368
|
-
|
|
2369
|
-
/**
|
|
2370
|
-
* @license
|
|
2371
|
-
* Copyright Google LLC All Rights Reserved.
|
|
2372
|
-
*
|
|
2373
|
-
* Use of this source code is governed by an MIT-style license that can be
|
|
2374
|
-
* found in the LICENSE file at https://angular.io/license
|
|
2375
|
-
*/
|
|
2376
|
-
/**
|
|
2377
|
-
* @description
|
|
2378
|
-
*
|
|
2379
|
-
* Acts as a placeholder that Angular dynamically fills based on the current router state.
|
|
2380
|
-
*
|
|
2381
|
-
* Each outlet can have a unique name, determined by the optional `name` attribute.
|
|
2382
|
-
* 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".
|
|
2383
2108
|
*
|
|
2384
2109
|
* ```
|
|
2385
2110
|
* <router-outlet></router-outlet>
|
|
@@ -2425,11 +2150,11 @@ class ChildrenOutletContexts {
|
|
|
2425
2150
|
* @publicApi
|
|
2426
2151
|
*/
|
|
2427
2152
|
class RouterOutlet {
|
|
2428
|
-
constructor(parentContexts, location,
|
|
2153
|
+
constructor(parentContexts, location, name, changeDetector, environmentInjector) {
|
|
2429
2154
|
this.parentContexts = parentContexts;
|
|
2430
2155
|
this.location = location;
|
|
2431
|
-
this.resolver = resolver;
|
|
2432
2156
|
this.changeDetector = changeDetector;
|
|
2157
|
+
this.environmentInjector = environmentInjector;
|
|
2433
2158
|
this.activated = null;
|
|
2434
2159
|
this._activatedRoute = null;
|
|
2435
2160
|
this.activateEvents = new EventEmitter();
|
|
@@ -2464,7 +2189,7 @@ class RouterOutlet {
|
|
|
2464
2189
|
}
|
|
2465
2190
|
else {
|
|
2466
2191
|
// otherwise the component defined in the configuration is created
|
|
2467
|
-
this.activateWith(context.route, context.
|
|
2192
|
+
this.activateWith(context.route, context.injector);
|
|
2468
2193
|
}
|
|
2469
2194
|
}
|
|
2470
2195
|
}
|
|
@@ -2523,33 +2248,39 @@ class RouterOutlet {
|
|
|
2523
2248
|
this.deactivateEvents.emit(c);
|
|
2524
2249
|
}
|
|
2525
2250
|
}
|
|
2526
|
-
activateWith(activatedRoute,
|
|
2251
|
+
activateWith(activatedRoute, resolverOrInjector) {
|
|
2527
2252
|
if (this.isActivated) {
|
|
2528
2253
|
throw new Error('Cannot activate an already activated outlet');
|
|
2529
2254
|
}
|
|
2530
2255
|
this._activatedRoute = activatedRoute;
|
|
2256
|
+
const location = this.location;
|
|
2531
2257
|
const snapshot = activatedRoute._futureSnapshot;
|
|
2532
2258
|
const component = snapshot.routeConfig.component;
|
|
2533
|
-
resolver = resolver || this.resolver;
|
|
2534
|
-
const factory = resolver.resolveComponentFactory(component);
|
|
2535
2259
|
const childContexts = this.parentContexts.getOrCreateContext(this.name).children;
|
|
2536
|
-
const injector = new OutletInjector(activatedRoute, childContexts,
|
|
2537
|
-
|
|
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
|
+
}
|
|
2538
2269
|
// Calling `markForCheck` to make sure we will run the change detection when the
|
|
2539
2270
|
// `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component.
|
|
2540
2271
|
this.changeDetector.markForCheck();
|
|
2541
2272
|
this.activateEvents.emit(this.activated.instance);
|
|
2542
2273
|
}
|
|
2543
2274
|
}
|
|
2544
|
-
RouterOutlet.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
2545
|
-
RouterOutlet.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
2546
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
2547
2278
|
type: Directive,
|
|
2548
2279
|
args: [{ selector: 'router-outlet', exportAs: 'outlet' }]
|
|
2549
|
-
}], ctorParameters: function () { return [{ type: ChildrenOutletContexts }, { type: i0.ViewContainerRef }, { type:
|
|
2280
|
+
}], ctorParameters: function () { return [{ type: ChildrenOutletContexts }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
|
|
2550
2281
|
type: Attribute,
|
|
2551
2282
|
args: ['name']
|
|
2552
|
-
}] }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { activateEvents: [{
|
|
2283
|
+
}] }, { type: i0.ChangeDetectorRef }, { type: i0.EnvironmentInjector }]; }, propDecorators: { activateEvents: [{
|
|
2553
2284
|
type: Output,
|
|
2554
2285
|
args: ['activate']
|
|
2555
2286
|
}], deactivateEvents: [{
|
|
@@ -2568,14 +2299,376 @@ class OutletInjector {
|
|
|
2568
2299
|
this.childContexts = childContexts;
|
|
2569
2300
|
this.parent = parent;
|
|
2570
2301
|
}
|
|
2571
|
-
get(token, notFoundValue) {
|
|
2572
|
-
if (token === ActivatedRoute) {
|
|
2573
|
-
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));
|
|
2574
2616
|
}
|
|
2575
|
-
|
|
2576
|
-
|
|
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
|
+
}
|
|
2633
|
+
}
|
|
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
|
+
}
|
|
2577
2671
|
}
|
|
2578
|
-
return this.parent.get(token, notFoundValue);
|
|
2579
2672
|
}
|
|
2580
2673
|
}
|
|
2581
2674
|
|
|
@@ -2587,22 +2680,39 @@ class OutletInjector {
|
|
|
2587
2680
|
* found in the LICENSE file at https://angular.io/license
|
|
2588
2681
|
*/
|
|
2589
2682
|
/**
|
|
2590
|
-
*
|
|
2591
|
-
* router-outlet is needed. For example, with a config such as:
|
|
2683
|
+
* Simple function check, but generic so type inference will flow. Example:
|
|
2592
2684
|
*
|
|
2593
|
-
*
|
|
2685
|
+
* function product(a: number, b: number) {
|
|
2686
|
+
* return a * b;
|
|
2687
|
+
* }
|
|
2594
2688
|
*
|
|
2595
|
-
*
|
|
2596
|
-
*
|
|
2689
|
+
* if (isFunction<product>(fn)) {
|
|
2690
|
+
* return fn(1, 2);
|
|
2691
|
+
* } else {
|
|
2692
|
+
* throw "Must provide the `product` function";
|
|
2693
|
+
* }
|
|
2597
2694
|
*/
|
|
2598
|
-
|
|
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);
|
|
2599
2715
|
}
|
|
2600
|
-
ɵEmptyOutletComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: ɵEmptyOutletComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2601
|
-
ɵEmptyOutletComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "14.0.0-next.13", 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"] }] });
|
|
2602
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.13", ngImport: i0, type: ɵEmptyOutletComponent, decorators: [{
|
|
2603
|
-
type: Component,
|
|
2604
|
-
args: [{ template: `<router-outlet></router-outlet>` }]
|
|
2605
|
-
}] });
|
|
2606
2716
|
|
|
2607
2717
|
/**
|
|
2608
2718
|
* @license
|
|
@@ -2611,113 +2721,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.13",
|
|
|
2611
2721
|
* Use of this source code is governed by an MIT-style license that can be
|
|
2612
2722
|
* found in the LICENSE file at https://angular.io/license
|
|
2613
2723
|
*/
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
if (route.redirectTo && route.children) {
|
|
2645
|
-
throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and children cannot be used together`);
|
|
2646
|
-
}
|
|
2647
|
-
if (route.redirectTo && route.loadChildren) {
|
|
2648
|
-
throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and loadChildren cannot be used together`);
|
|
2649
|
-
}
|
|
2650
|
-
if (route.children && route.loadChildren) {
|
|
2651
|
-
throw new Error(`Invalid configuration of route '${fullPath}': children and loadChildren cannot be used together`);
|
|
2652
|
-
}
|
|
2653
|
-
if (route.redirectTo && route.component) {
|
|
2654
|
-
throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and component cannot be used together`);
|
|
2655
|
-
}
|
|
2656
|
-
if (route.redirectTo && route.canActivate) {
|
|
2657
|
-
throw new Error(`Invalid configuration of route '${fullPath}': redirectTo and canActivate cannot be used together. Redirects happen before activation ` +
|
|
2658
|
-
`so canActivate will never be executed.`);
|
|
2659
|
-
}
|
|
2660
|
-
if (route.path && route.matcher) {
|
|
2661
|
-
throw new Error(`Invalid configuration of route '${fullPath}': path and matcher cannot be used together`);
|
|
2662
|
-
}
|
|
2663
|
-
if (route.redirectTo === void 0 && !route.component && !route.children && !route.loadChildren) {
|
|
2664
|
-
throw new Error(`Invalid configuration of route '${fullPath}'. One of the following must be provided: component, redirectTo, children or loadChildren`);
|
|
2665
|
-
}
|
|
2666
|
-
if (route.path === void 0 && route.matcher === void 0) {
|
|
2667
|
-
throw new Error(`Invalid configuration of route '${fullPath}': routes must have either a path or a matcher specified`);
|
|
2668
|
-
}
|
|
2669
|
-
if (typeof route.path === 'string' && route.path.charAt(0) === '/') {
|
|
2670
|
-
throw new Error(`Invalid configuration of route '${fullPath}': path cannot start with a slash`);
|
|
2671
|
-
}
|
|
2672
|
-
if (route.path === '' && route.redirectTo !== void 0 && route.pathMatch === void 0) {
|
|
2673
|
-
const exp = `The default value of 'pathMatch' is 'prefix', but often the intent is to use 'full'.`;
|
|
2674
|
-
throw new Error(`Invalid configuration of route '{path: "${fullPath}", redirectTo: "${route.redirectTo}"}': please provide 'pathMatch'. ${exp}`);
|
|
2675
|
-
}
|
|
2676
|
-
}
|
|
2677
|
-
if (route.children) {
|
|
2678
|
-
validateConfig(route.children, fullPath);
|
|
2679
|
-
}
|
|
2680
|
-
}
|
|
2681
|
-
function getFullPath(parentPath, currentRoute) {
|
|
2682
|
-
if (!currentRoute) {
|
|
2683
|
-
return parentPath;
|
|
2684
|
-
}
|
|
2685
|
-
if (!parentPath && !currentRoute.path) {
|
|
2686
|
-
return '';
|
|
2687
|
-
}
|
|
2688
|
-
else if (parentPath && !currentRoute.path) {
|
|
2689
|
-
return `${parentPath}/`;
|
|
2690
|
-
}
|
|
2691
|
-
else if (!parentPath && currentRoute.path) {
|
|
2692
|
-
return currentRoute.path;
|
|
2693
|
-
}
|
|
2694
|
-
else {
|
|
2695
|
-
return `${parentPath}/${currentRoute.path}`;
|
|
2696
|
-
}
|
|
2697
|
-
}
|
|
2698
|
-
/**
|
|
2699
|
-
* Makes a copy of the config and adds any default required properties.
|
|
2700
|
-
*/
|
|
2701
|
-
function standardizeConfig(r) {
|
|
2702
|
-
const children = r.children && r.children.map(standardizeConfig);
|
|
2703
|
-
const c = children ? { ...r, children } : { ...r };
|
|
2704
|
-
if (!c.component && (children || c.loadChildren) && (c.outlet && c.outlet !== PRIMARY_OUTLET)) {
|
|
2705
|
-
c.component = ɵEmptyOutletComponent;
|
|
2706
|
-
}
|
|
2707
|
-
return c;
|
|
2708
|
-
}
|
|
2709
|
-
/** Returns the `route.outlet` or PRIMARY_OUTLET if none exists. */
|
|
2710
|
-
function getOutlet(route) {
|
|
2711
|
-
return route.outlet || PRIMARY_OUTLET;
|
|
2712
|
-
}
|
|
2713
|
-
/**
|
|
2714
|
-
* Sorts the `routes` such that the ones with an outlet matching `outletName` come first.
|
|
2715
|
-
* The order of the configs is otherwise preserved.
|
|
2716
|
-
*/
|
|
2717
|
-
function sortByMatchingOutlets(routes, outletName) {
|
|
2718
|
-
const sortedConfig = routes.filter(r => getOutlet(r) === outletName);
|
|
2719
|
-
sortedConfig.push(...routes.filter(r => getOutlet(r) !== outletName));
|
|
2720
|
-
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
|
+
});
|
|
2721
2754
|
}
|
|
2722
2755
|
|
|
2723
2756
|
/**
|
|
@@ -2898,17 +2931,17 @@ function canLoadFails(route) {
|
|
|
2898
2931
|
*
|
|
2899
2932
|
* Lazy modules are loaded along the way.
|
|
2900
2933
|
*/
|
|
2901
|
-
function applyRedirects$1(
|
|
2902
|
-
return new ApplyRedirects(
|
|
2934
|
+
function applyRedirects$1(injector, configLoader, urlSerializer, urlTree, config) {
|
|
2935
|
+
return new ApplyRedirects(injector, configLoader, urlSerializer, urlTree, config).apply();
|
|
2903
2936
|
}
|
|
2904
2937
|
class ApplyRedirects {
|
|
2905
|
-
constructor(
|
|
2938
|
+
constructor(injector, configLoader, urlSerializer, urlTree, config) {
|
|
2939
|
+
this.injector = injector;
|
|
2906
2940
|
this.configLoader = configLoader;
|
|
2907
2941
|
this.urlSerializer = urlSerializer;
|
|
2908
2942
|
this.urlTree = urlTree;
|
|
2909
2943
|
this.config = config;
|
|
2910
2944
|
this.allowRedirects = true;
|
|
2911
|
-
this.ngModule = moduleInjector.get(NgModuleRef);
|
|
2912
2945
|
}
|
|
2913
2946
|
apply() {
|
|
2914
2947
|
const splitGroup = split(this.urlTree.root, [], [], this.config).segmentGroup;
|
|
@@ -2919,7 +2952,7 @@ class ApplyRedirects {
|
|
|
2919
2952
|
// them. We should be able to remove this logic as a "breaking change" but should do some more
|
|
2920
2953
|
// investigation into the failures first.
|
|
2921
2954
|
const rootSegmentGroup = new UrlSegmentGroup(splitGroup.segments, splitGroup.children);
|
|
2922
|
-
const expanded$ = this.expandSegmentGroup(this.
|
|
2955
|
+
const expanded$ = this.expandSegmentGroup(this.injector, this.config, rootSegmentGroup, PRIMARY_OUTLET);
|
|
2923
2956
|
const urlTrees$ = expanded$.pipe(map((rootSegmentGroup) => {
|
|
2924
2957
|
return this.createUrlTree(squashSegmentGroup(rootSegmentGroup), this.urlTree.queryParams, this.urlTree.fragment);
|
|
2925
2958
|
}));
|
|
@@ -2938,7 +2971,7 @@ class ApplyRedirects {
|
|
|
2938
2971
|
}));
|
|
2939
2972
|
}
|
|
2940
2973
|
match(tree) {
|
|
2941
|
-
const expanded$ = this.expandSegmentGroup(this.
|
|
2974
|
+
const expanded$ = this.expandSegmentGroup(this.injector, this.config, tree.root, PRIMARY_OUTLET);
|
|
2942
2975
|
const mapped$ = expanded$.pipe(map((rootSegmentGroup) => {
|
|
2943
2976
|
return this.createUrlTree(squashSegmentGroup(rootSegmentGroup), tree.queryParams, tree.fragment);
|
|
2944
2977
|
}));
|
|
@@ -2958,15 +2991,15 @@ class ApplyRedirects {
|
|
|
2958
2991
|
rootCandidate;
|
|
2959
2992
|
return new UrlTree(root, queryParams, fragment);
|
|
2960
2993
|
}
|
|
2961
|
-
expandSegmentGroup(
|
|
2994
|
+
expandSegmentGroup(injector, routes, segmentGroup, outlet) {
|
|
2962
2995
|
if (segmentGroup.segments.length === 0 && segmentGroup.hasChildren()) {
|
|
2963
|
-
return this.expandChildren(
|
|
2996
|
+
return this.expandChildren(injector, routes, segmentGroup)
|
|
2964
2997
|
.pipe(map((children) => new UrlSegmentGroup([], children)));
|
|
2965
2998
|
}
|
|
2966
|
-
return this.expandSegment(
|
|
2999
|
+
return this.expandSegment(injector, segmentGroup, routes, segmentGroup.segments, outlet, true);
|
|
2967
3000
|
}
|
|
2968
3001
|
// Recursively expand segment groups for all the child outlets
|
|
2969
|
-
expandChildren(
|
|
3002
|
+
expandChildren(injector, routes, segmentGroup) {
|
|
2970
3003
|
// Expand outlets one at a time, starting with the primary outlet. We need to do it this way
|
|
2971
3004
|
// because an absolute redirect from the primary outlet takes precedence.
|
|
2972
3005
|
const childOutlets = [];
|
|
@@ -2985,16 +3018,25 @@ class ApplyRedirects {
|
|
|
2985
3018
|
// first, followed by routes for other outlets, which might match if they have an
|
|
2986
3019
|
// empty path.
|
|
2987
3020
|
const sortedRoutes = sortByMatchingOutlets(routes, childOutlet);
|
|
2988
|
-
return this.expandSegmentGroup(
|
|
3021
|
+
return this.expandSegmentGroup(injector, sortedRoutes, child, childOutlet)
|
|
2989
3022
|
.pipe(map(s => ({ segment: s, outlet: childOutlet })));
|
|
2990
3023
|
}), scan((children, expandedChild) => {
|
|
2991
3024
|
children[expandedChild.outlet] = expandedChild.segment;
|
|
2992
3025
|
return children;
|
|
2993
3026
|
}, {}), last$1());
|
|
2994
3027
|
}
|
|
2995
|
-
expandSegment(
|
|
2996
|
-
return from(routes).pipe(concatMap(
|
|
2997
|
-
|
|
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);
|
|
2998
3040
|
return expanded$.pipe(catchError((e) => {
|
|
2999
3041
|
if (e instanceof NoMatch$1) {
|
|
3000
3042
|
return of(null);
|
|
@@ -3011,35 +3053,35 @@ class ApplyRedirects {
|
|
|
3011
3053
|
throw e;
|
|
3012
3054
|
}));
|
|
3013
3055
|
}
|
|
3014
|
-
expandSegmentAgainstRoute(
|
|
3056
|
+
expandSegmentAgainstRoute(injector, segmentGroup, routes, route, paths, outlet, allowRedirects) {
|
|
3015
3057
|
if (!isImmediateMatch(route, segmentGroup, paths, outlet)) {
|
|
3016
3058
|
return noMatch(segmentGroup);
|
|
3017
3059
|
}
|
|
3018
3060
|
if (route.redirectTo === undefined) {
|
|
3019
|
-
return this.matchSegmentAgainstRoute(
|
|
3061
|
+
return this.matchSegmentAgainstRoute(injector, segmentGroup, route, paths, outlet);
|
|
3020
3062
|
}
|
|
3021
3063
|
if (allowRedirects && this.allowRedirects) {
|
|
3022
|
-
return this.expandSegmentAgainstRouteUsingRedirect(
|
|
3064
|
+
return this.expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, paths, outlet);
|
|
3023
3065
|
}
|
|
3024
3066
|
return noMatch(segmentGroup);
|
|
3025
3067
|
}
|
|
3026
|
-
expandSegmentAgainstRouteUsingRedirect(
|
|
3068
|
+
expandSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
|
|
3027
3069
|
if (route.path === '**') {
|
|
3028
|
-
return this.expandWildCardWithParamsAgainstRouteUsingRedirect(
|
|
3070
|
+
return this.expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet);
|
|
3029
3071
|
}
|
|
3030
|
-
return this.expandRegularSegmentAgainstRouteUsingRedirect(
|
|
3072
|
+
return this.expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet);
|
|
3031
3073
|
}
|
|
3032
|
-
expandWildCardWithParamsAgainstRouteUsingRedirect(
|
|
3074
|
+
expandWildCardWithParamsAgainstRouteUsingRedirect(injector, routes, route, outlet) {
|
|
3033
3075
|
const newTree = this.applyRedirectCommands([], route.redirectTo, {});
|
|
3034
3076
|
if (route.redirectTo.startsWith('/')) {
|
|
3035
3077
|
return absoluteRedirect(newTree);
|
|
3036
3078
|
}
|
|
3037
3079
|
return this.lineralizeSegments(route, newTree).pipe(mergeMap((newSegments) => {
|
|
3038
3080
|
const group = new UrlSegmentGroup(newSegments, {});
|
|
3039
|
-
return this.expandSegment(
|
|
3081
|
+
return this.expandSegment(injector, group, routes, newSegments, outlet, false);
|
|
3040
3082
|
}));
|
|
3041
3083
|
}
|
|
3042
|
-
expandRegularSegmentAgainstRouteUsingRedirect(
|
|
3084
|
+
expandRegularSegmentAgainstRouteUsingRedirect(injector, segmentGroup, routes, route, segments, outlet) {
|
|
3043
3085
|
const { matched, consumedSegments, remainingSegments, positionalParamSegments } = match(segmentGroup, route, segments);
|
|
3044
3086
|
if (!matched)
|
|
3045
3087
|
return noMatch(segmentGroup);
|
|
@@ -3048,16 +3090,18 @@ class ApplyRedirects {
|
|
|
3048
3090
|
return absoluteRedirect(newTree);
|
|
3049
3091
|
}
|
|
3050
3092
|
return this.lineralizeSegments(route, newTree).pipe(mergeMap((newSegments) => {
|
|
3051
|
-
return this.expandSegment(
|
|
3093
|
+
return this.expandSegment(injector, segmentGroup, routes, newSegments.concat(remainingSegments), outlet, false);
|
|
3052
3094
|
}));
|
|
3053
3095
|
}
|
|
3054
|
-
matchSegmentAgainstRoute(
|
|
3096
|
+
matchSegmentAgainstRoute(injector, rawSegmentGroup, route, segments, outlet) {
|
|
3055
3097
|
if (route.path === '**') {
|
|
3056
3098
|
if (route.loadChildren) {
|
|
3057
|
-
const loaded$ = route.
|
|
3058
|
-
|
|
3099
|
+
const loaded$ = route._loadedRoutes ?
|
|
3100
|
+
of({ routes: route._loadedRoutes, injector: route._loadedInjector }) :
|
|
3101
|
+
this.configLoader.load(injector, route);
|
|
3059
3102
|
return loaded$.pipe(map((cfg) => {
|
|
3060
|
-
route.
|
|
3103
|
+
route._loadedRoutes = cfg.routes;
|
|
3104
|
+
route._loadedInjector = cfg.injector;
|
|
3061
3105
|
return new UrlSegmentGroup(segments, {});
|
|
3062
3106
|
}));
|
|
3063
3107
|
}
|
|
@@ -3066,55 +3110,55 @@ class ApplyRedirects {
|
|
|
3066
3110
|
const { matched, consumedSegments, remainingSegments } = match(rawSegmentGroup, route, segments);
|
|
3067
3111
|
if (!matched)
|
|
3068
3112
|
return noMatch(rawSegmentGroup);
|
|
3069
|
-
const childConfig$ = this.getChildConfig(
|
|
3113
|
+
const childConfig$ = this.getChildConfig(injector, route, segments);
|
|
3070
3114
|
return childConfig$.pipe(mergeMap((routerConfig) => {
|
|
3071
|
-
const
|
|
3115
|
+
const childInjector = routerConfig.injector ?? injector;
|
|
3072
3116
|
const childConfig = routerConfig.routes;
|
|
3073
3117
|
const { segmentGroup: splitSegmentGroup, slicedSegments } = split(rawSegmentGroup, consumedSegments, remainingSegments, childConfig);
|
|
3074
3118
|
// See comment on the other call to `split` about why this is necessary.
|
|
3075
3119
|
const segmentGroup = new UrlSegmentGroup(splitSegmentGroup.segments, splitSegmentGroup.children);
|
|
3076
3120
|
if (slicedSegments.length === 0 && segmentGroup.hasChildren()) {
|
|
3077
|
-
const expanded$ = this.expandChildren(
|
|
3121
|
+
const expanded$ = this.expandChildren(childInjector, childConfig, segmentGroup);
|
|
3078
3122
|
return expanded$.pipe(map((children) => new UrlSegmentGroup(consumedSegments, children)));
|
|
3079
3123
|
}
|
|
3080
3124
|
if (childConfig.length === 0 && slicedSegments.length === 0) {
|
|
3081
3125
|
return of(new UrlSegmentGroup(consumedSegments, {}));
|
|
3082
3126
|
}
|
|
3083
3127
|
const matchedOnOutlet = getOutlet(route) === outlet;
|
|
3084
|
-
const expanded$ = this.expandSegment(
|
|
3128
|
+
const expanded$ = this.expandSegment(childInjector, segmentGroup, childConfig, slicedSegments, matchedOnOutlet ? PRIMARY_OUTLET : outlet, true);
|
|
3085
3129
|
return expanded$.pipe(map((cs) => new UrlSegmentGroup(consumedSegments.concat(cs.segments), cs.children)));
|
|
3086
3130
|
}));
|
|
3087
3131
|
}
|
|
3088
|
-
getChildConfig(
|
|
3132
|
+
getChildConfig(injector, route, segments) {
|
|
3089
3133
|
if (route.children) {
|
|
3090
3134
|
// The children belong to the same module
|
|
3091
|
-
return of(
|
|
3135
|
+
return of({ routes: route.children, injector });
|
|
3092
3136
|
}
|
|
3093
3137
|
if (route.loadChildren) {
|
|
3094
3138
|
// lazy children belong to the loaded module
|
|
3095
|
-
if (route.
|
|
3096
|
-
return of(route.
|
|
3139
|
+
if (route._loadedRoutes !== undefined) {
|
|
3140
|
+
return of({ routes: route._loadedRoutes, injector: route._loadedInjector });
|
|
3097
3141
|
}
|
|
3098
|
-
return this.runCanLoadGuards(
|
|
3142
|
+
return this.runCanLoadGuards(injector, route, segments)
|
|
3099
3143
|
.pipe(mergeMap((shouldLoadResult) => {
|
|
3100
3144
|
if (shouldLoadResult) {
|
|
3101
|
-
return this.configLoader.load(
|
|
3102
|
-
.
|
|
3103
|
-
route.
|
|
3145
|
+
return this.configLoader.load(injector, route).pipe(map((cfg) => {
|
|
3146
|
+
route._loadedRoutes = cfg.routes;
|
|
3147
|
+
route._loadedInjector = cfg.injector;
|
|
3104
3148
|
return cfg;
|
|
3105
3149
|
}));
|
|
3106
3150
|
}
|
|
3107
3151
|
return canLoadFails(route);
|
|
3108
3152
|
}));
|
|
3109
3153
|
}
|
|
3110
|
-
return of(
|
|
3154
|
+
return of({ routes: [], injector });
|
|
3111
3155
|
}
|
|
3112
|
-
runCanLoadGuards(
|
|
3156
|
+
runCanLoadGuards(injector, route, segments) {
|
|
3113
3157
|
const canLoad = route.canLoad;
|
|
3114
3158
|
if (!canLoad || canLoad.length === 0)
|
|
3115
3159
|
return of(true);
|
|
3116
3160
|
const canLoadObservables = canLoad.map((injectionToken) => {
|
|
3117
|
-
const guard =
|
|
3161
|
+
const guard = injector.get(injectionToken);
|
|
3118
3162
|
let guardVal;
|
|
3119
3163
|
if (isCanLoad(guard)) {
|
|
3120
3164
|
guardVal = guard.canLoad(route, segments);
|
|
@@ -3242,8 +3286,8 @@ function squashSegmentGroup(segmentGroup) {
|
|
|
3242
3286
|
* Use of this source code is governed by an MIT-style license that can be
|
|
3243
3287
|
* found in the LICENSE file at https://angular.io/license
|
|
3244
3288
|
*/
|
|
3245
|
-
function applyRedirects(
|
|
3246
|
-
return switchMap(t => applyRedirects$1(
|
|
3289
|
+
function applyRedirects(environmentInjector, configLoader, urlSerializer, config) {
|
|
3290
|
+
return switchMap(t => applyRedirects$1(environmentInjector, configLoader, urlSerializer, t.extractedUrl, config)
|
|
3247
3291
|
.pipe(map(urlAfterRedirects => ({ ...t, urlAfterRedirects }))));
|
|
3248
3292
|
}
|
|
3249
3293
|
|
|
@@ -3277,21 +3321,11 @@ function getCanActivateChild(p) {
|
|
|
3277
3321
|
return null;
|
|
3278
3322
|
return { node: p, guards: canActivateChild };
|
|
3279
3323
|
}
|
|
3280
|
-
function getToken(token, snapshot,
|
|
3281
|
-
const
|
|
3282
|
-
const injector =
|
|
3324
|
+
function getToken(token, snapshot, fallbackInjector) {
|
|
3325
|
+
const routeInjector = getClosestRouteInjector(snapshot);
|
|
3326
|
+
const injector = routeInjector ?? fallbackInjector;
|
|
3283
3327
|
return injector.get(token);
|
|
3284
3328
|
}
|
|
3285
|
-
function getClosestLoadedConfig(snapshot) {
|
|
3286
|
-
if (!snapshot)
|
|
3287
|
-
return null;
|
|
3288
|
-
for (let s = snapshot.parent; s; s = s.parent) {
|
|
3289
|
-
const route = s.routeConfig;
|
|
3290
|
-
if (route && route._loadedConfig)
|
|
3291
|
-
return route._loadedConfig;
|
|
3292
|
-
}
|
|
3293
|
-
return null;
|
|
3294
|
-
}
|
|
3295
3329
|
function getChildRouteGuards(futureNode, currNode, contexts, futurePath, checks = {
|
|
3296
3330
|
canDeactivateChecks: [],
|
|
3297
3331
|
canActivateChecks: []
|
|
@@ -3535,7 +3569,7 @@ function runCanDeactivate(component, currARS, currRSS, futureRSS, moduleInjector
|
|
|
3535
3569
|
* Use of this source code is governed by an MIT-style license that can be
|
|
3536
3570
|
* found in the LICENSE file at https://angular.io/license
|
|
3537
3571
|
*/
|
|
3538
|
-
const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
|
|
3572
|
+
const NG_DEV_MODE$2 = typeof ngDevMode === 'undefined' || !!ngDevMode;
|
|
3539
3573
|
class NoMatch {
|
|
3540
3574
|
}
|
|
3541
3575
|
function newObservableError(e) {
|
|
@@ -3656,7 +3690,7 @@ class Recognizer {
|
|
|
3656
3690
|
// NG_DEV_MODE is used to prevent the getCorrectedPathIndexShift function from affecting
|
|
3657
3691
|
// production bundle size. This value is intended only to surface a warning to users
|
|
3658
3692
|
// depending on `relativeLinkResolution: 'legacy'` in dev mode.
|
|
3659
|
-
(NG_DEV_MODE ? getCorrectedPathIndexShift(rawSegment) + segments.length :
|
|
3693
|
+
(NG_DEV_MODE$2 ? getCorrectedPathIndexShift(rawSegment) + segments.length :
|
|
3660
3694
|
pathIndexShift));
|
|
3661
3695
|
}
|
|
3662
3696
|
else {
|
|
@@ -3667,7 +3701,7 @@ class Recognizer {
|
|
|
3667
3701
|
consumedSegments = result.consumedSegments;
|
|
3668
3702
|
remainingSegments = result.remainingSegments;
|
|
3669
3703
|
const pathIndexShift = getPathIndexShift(rawSegment) + consumedSegments.length;
|
|
3670
|
-
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 ? getCorrectedPathIndexShift(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 :
|
|
3671
3705
|
pathIndexShift));
|
|
3672
3706
|
}
|
|
3673
3707
|
const childConfig = getChildConfig(route);
|
|
@@ -3716,7 +3750,7 @@ function getChildConfig(route) {
|
|
|
3716
3750
|
return route.children;
|
|
3717
3751
|
}
|
|
3718
3752
|
if (route.loadChildren) {
|
|
3719
|
-
return route.
|
|
3753
|
+
return route._loadedRoutes;
|
|
3720
3754
|
}
|
|
3721
3755
|
return [];
|
|
3722
3756
|
}
|
|
@@ -3860,16 +3894,9 @@ function resolveNode(resolve, futureARS, futureRSS, moduleInjector) {
|
|
|
3860
3894
|
}
|
|
3861
3895
|
const data = {};
|
|
3862
3896
|
return from(keys).pipe(mergeMap(key => getResolver(resolve[key], futureARS, futureRSS, moduleInjector)
|
|
3863
|
-
.pipe(
|
|
3897
|
+
.pipe(first(), tap((value) => {
|
|
3864
3898
|
data[key] = value;
|
|
3865
|
-
}))), takeLast(1),
|
|
3866
|
-
// Ensure all resolvers returned values, otherwise don't emit any "next" and just complete
|
|
3867
|
-
// the chain which will cancel navigation
|
|
3868
|
-
if (getDataKeys(data).length === keys.length) {
|
|
3869
|
-
return of(data);
|
|
3870
|
-
}
|
|
3871
|
-
return EMPTY;
|
|
3872
|
-
}));
|
|
3899
|
+
}))), takeLast(1), mapTo(data), catchError((e) => e instanceof EmptyError ? EMPTY : throwError(e)));
|
|
3873
3900
|
}
|
|
3874
3901
|
function getDataKeys(obj) {
|
|
3875
3902
|
return [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
|
|
@@ -3978,6 +4005,7 @@ class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
|
|
|
3978
4005
|
* Use of this source code is governed by an MIT-style license that can be
|
|
3979
4006
|
* found in the LICENSE file at https://angular.io/license
|
|
3980
4007
|
*/
|
|
4008
|
+
const NG_DEV_MODE$1 = typeof ngDevMode === 'undefined' || !!ngDevMode;
|
|
3981
4009
|
/**
|
|
3982
4010
|
* The [DI token](guide/glossary/#di-token) for a router configuration.
|
|
3983
4011
|
*
|
|
@@ -3990,15 +4018,17 @@ class DefaultRouteReuseStrategy extends BaseRouteReuseStrategy {
|
|
|
3990
4018
|
*/
|
|
3991
4019
|
const ROUTES = new InjectionToken('ROUTES');
|
|
3992
4020
|
class RouterConfigLoader {
|
|
3993
|
-
constructor(injector, compiler
|
|
4021
|
+
constructor(injector, compiler) {
|
|
3994
4022
|
this.injector = injector;
|
|
3995
4023
|
this.compiler = compiler;
|
|
3996
|
-
this.
|
|
3997
|
-
this.onLoadEndListener = onLoadEndListener;
|
|
4024
|
+
this.routeLoaders = new WeakMap();
|
|
3998
4025
|
}
|
|
3999
4026
|
load(parentInjector, route) {
|
|
4000
|
-
if (route
|
|
4001
|
-
return route
|
|
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 });
|
|
4002
4032
|
}
|
|
4003
4033
|
if (this.onLoadStartListener) {
|
|
4004
4034
|
this.onLoadStartListener(route);
|
|
@@ -4008,21 +4038,24 @@ class RouterConfigLoader {
|
|
|
4008
4038
|
if (this.onLoadEndListener) {
|
|
4009
4039
|
this.onLoadEndListener(route);
|
|
4010
4040
|
}
|
|
4011
|
-
const
|
|
4041
|
+
const injector = factory.create(parentInjector).injector;
|
|
4042
|
+
const routes =
|
|
4012
4043
|
// When loading a module that doesn't provide `RouterModule.forChild()` preloader
|
|
4013
4044
|
// will get stuck in an infinite loop. The child module's Injector will look to
|
|
4014
4045
|
// its parent `Injector` when it doesn't find any ROUTES so it will return routes
|
|
4015
4046
|
// for it's parent module instead.
|
|
4016
|
-
|
|
4017
|
-
.map(standardizeConfig)
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
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);
|
|
4021
4053
|
}));
|
|
4022
4054
|
// Use custom ConnectableObservable as share in runners pipe increasing the bundle size too much
|
|
4023
|
-
|
|
4055
|
+
const loader = new ConnectableObservable(loadRunner, () => new Subject())
|
|
4024
4056
|
.pipe(refCount());
|
|
4025
|
-
|
|
4057
|
+
this.routeLoaders.set(route, loader);
|
|
4058
|
+
return loader;
|
|
4026
4059
|
}
|
|
4027
4060
|
loadModuleFactory(loadChildren) {
|
|
4028
4061
|
return wrapIntoObservable(loadChildren()).pipe(mergeMap((t) => {
|
|
@@ -4035,6 +4068,11 @@ class RouterConfigLoader {
|
|
|
4035
4068
|
}));
|
|
4036
4069
|
}
|
|
4037
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 }]; } });
|
|
4038
4076
|
|
|
4039
4077
|
/**
|
|
4040
4078
|
* @license
|
|
@@ -4074,6 +4112,7 @@ class DefaultUrlHandlingStrategy {
|
|
|
4074
4112
|
* Use of this source code is governed by an MIT-style license that can be
|
|
4075
4113
|
* found in the LICENSE file at https://angular.io/license
|
|
4076
4114
|
*/
|
|
4115
|
+
const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
|
|
4077
4116
|
function defaultErrorHandler(error) {
|
|
4078
4117
|
throw error;
|
|
4079
4118
|
}
|
|
@@ -4245,6 +4284,9 @@ class Router {
|
|
|
4245
4284
|
this.canceledNavigationResolution = 'replace';
|
|
4246
4285
|
const onLoadStart = (r) => this.triggerEvent(new RouteConfigLoadStart(r));
|
|
4247
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;
|
|
4248
4290
|
this.ngModule = injector.get(NgModuleRef);
|
|
4249
4291
|
this.console = injector.get(ɵConsole);
|
|
4250
4292
|
const ngZone = injector.get(NgZone);
|
|
@@ -4253,7 +4295,6 @@ class Router {
|
|
|
4253
4295
|
this.currentUrlTree = createEmptyUrlTree();
|
|
4254
4296
|
this.rawUrlTree = this.currentUrlTree;
|
|
4255
4297
|
this.browserUrlTree = this.currentUrlTree;
|
|
4256
|
-
this.configLoader = new RouterConfigLoader(injector, compiler, onLoadStart, onLoadEnd);
|
|
4257
4298
|
this.routerState = createEmptyState(this.currentUrlTree, this.rootComponentType);
|
|
4258
4299
|
this.transitions = new BehaviorSubject({
|
|
4259
4300
|
id: 0,
|
|
@@ -4666,7 +4707,7 @@ class Router {
|
|
|
4666
4707
|
* ```
|
|
4667
4708
|
*/
|
|
4668
4709
|
resetConfig(config) {
|
|
4669
|
-
validateConfig(config);
|
|
4710
|
+
NG_DEV_MODE && validateConfig(config);
|
|
4670
4711
|
this.config = config.map(standardizeConfig);
|
|
4671
4712
|
this.navigated = false;
|
|
4672
4713
|
this.lastSuccessfulId = -1;
|
|
@@ -5021,9 +5062,9 @@ class Router {
|
|
|
5021
5062
|
return { navigationId };
|
|
5022
5063
|
}
|
|
5023
5064
|
}
|
|
5024
|
-
Router.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5025
|
-
Router.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5026
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
5027
5068
|
type: Injectable
|
|
5028
5069
|
}], ctorParameters: function () { return [{ type: i0.Type }, { type: UrlSerializer }, { type: ChildrenOutletContexts }, { type: i3.Location }, { type: i0.Injector }, { type: i0.Compiler }, { type: undefined }]; } });
|
|
5029
5070
|
function validateCommands(commands) {
|
|
@@ -5222,9 +5263,9 @@ class RouterLink {
|
|
|
5222
5263
|
});
|
|
5223
5264
|
}
|
|
5224
5265
|
}
|
|
5225
|
-
RouterLink.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5226
|
-
RouterLink.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5227
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
5228
5269
|
type: Directive,
|
|
5229
5270
|
args: [{ selector: ':not(a):not(area)[routerLink]' }]
|
|
5230
5271
|
}], ctorParameters: function () { return [{ type: Router }, { type: ActivatedRoute }, { type: undefined, decorators: [{
|
|
@@ -5341,9 +5382,9 @@ class RouterLinkWithHref {
|
|
|
5341
5382
|
});
|
|
5342
5383
|
}
|
|
5343
5384
|
}
|
|
5344
|
-
RouterLinkWithHref.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5345
|
-
RouterLinkWithHref.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5346
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
5347
5388
|
type: Directive,
|
|
5348
5389
|
args: [{ selector: 'a[routerLink],area[routerLink]' }]
|
|
5349
5390
|
}], ctorParameters: function () { return [{ type: Router }, { type: ActivatedRoute }, { type: i3.LocationStrategy }]; }, propDecorators: { target: [{
|
|
@@ -5552,9 +5593,9 @@ class RouterLinkActive {
|
|
|
5552
5593
|
this.links.some(isActiveCheckFn) || this.linksWithHrefs.some(isActiveCheckFn);
|
|
5553
5594
|
}
|
|
5554
5595
|
}
|
|
5555
|
-
RouterLinkActive.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5556
|
-
RouterLinkActive.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5557
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
5558
5599
|
type: Directive,
|
|
5559
5600
|
args: [{
|
|
5560
5601
|
selector: '[routerLinkActive]',
|
|
@@ -5655,9 +5696,9 @@ class DefaultTitleStrategy extends TitleStrategy {
|
|
|
5655
5696
|
}
|
|
5656
5697
|
}
|
|
5657
5698
|
}
|
|
5658
|
-
DefaultTitleStrategy.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5659
|
-
DefaultTitleStrategy.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5660
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
5661
5702
|
type: Injectable,
|
|
5662
5703
|
args: [{ providedIn: 'root' }]
|
|
5663
5704
|
}], ctorParameters: function () { return [{ type: i1.Title }]; } });
|
|
@@ -5721,13 +5762,11 @@ class NoPreloading {
|
|
|
5721
5762
|
* @publicApi
|
|
5722
5763
|
*/
|
|
5723
5764
|
class RouterPreloader {
|
|
5724
|
-
constructor(router, compiler, injector, preloadingStrategy) {
|
|
5765
|
+
constructor(router, compiler, injector, preloadingStrategy, loader) {
|
|
5725
5766
|
this.router = router;
|
|
5726
5767
|
this.injector = injector;
|
|
5727
5768
|
this.preloadingStrategy = preloadingStrategy;
|
|
5728
|
-
|
|
5729
|
-
const onEndLoad = (r) => router.triggerEvent(new RouteConfigLoadEnd(r));
|
|
5730
|
-
this.loader = new RouterConfigLoader(injector, compiler, onStartLoad, onEndLoad);
|
|
5769
|
+
this.loader = loader;
|
|
5731
5770
|
}
|
|
5732
5771
|
setUpPreloading() {
|
|
5733
5772
|
this.subscription =
|
|
@@ -5736,8 +5775,7 @@ class RouterPreloader {
|
|
|
5736
5775
|
.subscribe(() => { });
|
|
5737
5776
|
}
|
|
5738
5777
|
preload() {
|
|
5739
|
-
|
|
5740
|
-
return this.processRoutes(ngModule, this.router.config);
|
|
5778
|
+
return this.processRoutes(this.injector, this.router.config);
|
|
5741
5779
|
}
|
|
5742
5780
|
/** @nodoc */
|
|
5743
5781
|
ngOnDestroy() {
|
|
@@ -5745,41 +5783,50 @@ class RouterPreloader {
|
|
|
5745
5783
|
this.subscription.unsubscribe();
|
|
5746
5784
|
}
|
|
5747
5785
|
}
|
|
5748
|
-
processRoutes(
|
|
5786
|
+
processRoutes(injector, routes) {
|
|
5749
5787
|
const res = [];
|
|
5750
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;
|
|
5751
5795
|
// we already have the config loaded, just recurse
|
|
5752
|
-
if (route.loadChildren && !route.canLoad && route.
|
|
5753
|
-
|
|
5754
|
-
res.push(this.processRoutes(childConfig.module, childConfig.routes));
|
|
5796
|
+
if (route.loadChildren && !route.canLoad && route._loadedRoutes) {
|
|
5797
|
+
res.push(this.processRoutes(injectorForChildren, route._loadedRoutes));
|
|
5755
5798
|
// no config loaded, fetch the config
|
|
5756
5799
|
}
|
|
5757
5800
|
else if (route.loadChildren && !route.canLoad) {
|
|
5758
|
-
res.push(this.preloadConfig(
|
|
5801
|
+
res.push(this.preloadConfig(injectorForCurrentRoute, route));
|
|
5759
5802
|
// recurse into children
|
|
5760
5803
|
}
|
|
5761
5804
|
else if (route.children) {
|
|
5762
|
-
res.push(this.processRoutes(
|
|
5805
|
+
res.push(this.processRoutes(injectorForChildren, route.children));
|
|
5763
5806
|
}
|
|
5764
5807
|
}
|
|
5765
5808
|
return from(res).pipe(mergeAll(), map((_) => void 0));
|
|
5766
5809
|
}
|
|
5767
|
-
preloadConfig(
|
|
5810
|
+
preloadConfig(injector, route) {
|
|
5768
5811
|
return this.preloadingStrategy.preload(route, () => {
|
|
5769
|
-
const loaded$ = route.
|
|
5770
|
-
|
|
5812
|
+
const loaded$ = route._loadedRoutes ?
|
|
5813
|
+
of({ routes: route._loadedRoutes, injector: route._loadedInjector }) :
|
|
5814
|
+
this.loader.load(injector, route);
|
|
5771
5815
|
return loaded$.pipe(mergeMap((config) => {
|
|
5772
|
-
route.
|
|
5773
|
-
|
|
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);
|
|
5774
5821
|
}));
|
|
5775
5822
|
});
|
|
5776
5823
|
}
|
|
5777
5824
|
}
|
|
5778
|
-
RouterPreloader.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5779
|
-
RouterPreloader.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5780
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
5781
5828
|
type: Injectable
|
|
5782
|
-
}], ctorParameters: function () { return [{ type: Router }, { type: i0.Compiler }, { type: i0.
|
|
5829
|
+
}], ctorParameters: function () { return [{ type: Router }, { type: i0.Compiler }, { type: i0.EnvironmentInjector }, { type: PreloadingStrategy }, { type: RouterConfigLoader }]; } });
|
|
5783
5830
|
|
|
5784
5831
|
/**
|
|
5785
5832
|
* @license
|
|
@@ -5863,9 +5910,9 @@ class RouterScroller {
|
|
|
5863
5910
|
}
|
|
5864
5911
|
}
|
|
5865
5912
|
}
|
|
5866
|
-
RouterScroller.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5867
|
-
RouterScroller.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
5868
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
5869
5916
|
type: Injectable
|
|
5870
5917
|
}], ctorParameters: function () { return [{ type: Router }, { type: i3.ViewportScroller }, { type: undefined }]; } });
|
|
5871
5918
|
|
|
@@ -5908,6 +5955,7 @@ const ROUTER_PROVIDERS = [
|
|
|
5908
5955
|
NoPreloading,
|
|
5909
5956
|
PreloadAllModules,
|
|
5910
5957
|
{ provide: ROUTER_CONFIGURATION, useValue: { enableTracing: false } },
|
|
5958
|
+
RouterConfigLoader,
|
|
5911
5959
|
];
|
|
5912
5960
|
function routerNgProbeToken() {
|
|
5913
5961
|
return new NgProbeToken('Router', Router);
|
|
@@ -6006,10 +6054,10 @@ class RouterModule {
|
|
|
6006
6054
|
return { ngModule: RouterModule, providers: [provideRoutes(routes)] };
|
|
6007
6055
|
}
|
|
6008
6056
|
}
|
|
6009
|
-
RouterModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
6010
|
-
RouterModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
6011
|
-
RouterModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
6012
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
6013
6061
|
type: NgModule,
|
|
6014
6062
|
args: [{
|
|
6015
6063
|
declarations: ROUTER_DIRECTIVES,
|
|
@@ -6188,9 +6236,9 @@ class RouterInitializer {
|
|
|
6188
6236
|
this.destroyed = true;
|
|
6189
6237
|
}
|
|
6190
6238
|
}
|
|
6191
|
-
RouterInitializer.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
6192
|
-
RouterInitializer.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
6193
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.0-next.
|
|
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: [{
|
|
6194
6242
|
type: Injectable
|
|
6195
6243
|
}], ctorParameters: function () { return [{ type: i0.Injector }]; } });
|
|
6196
6244
|
function getAppInitializer(r) {
|
|
@@ -6230,7 +6278,7 @@ function provideRouterInitializer() {
|
|
|
6230
6278
|
/**
|
|
6231
6279
|
* @publicApi
|
|
6232
6280
|
*/
|
|
6233
|
-
const VERSION = new Version('14.0.0-next.
|
|
6281
|
+
const VERSION = new Version('14.0.0-next.14');
|
|
6234
6282
|
|
|
6235
6283
|
/**
|
|
6236
6284
|
* @license
|