Skip to content

Commit 1ab461c

Browse files
atscottkirjs
authored andcommitted
refactor(router): Store route injector on ActivatedRoute instance
This eliminates the need to pass around the EnvironmentInjector everywhere we need the injection context for a route.
1 parent c25d749 commit 1ab461c

File tree

14 files changed

+68
-156
lines changed

14 files changed

+68
-156
lines changed

packages/core/test/bundling/router/bundle.golden_symbols.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,6 @@
631631
"getCanActivateChild",
632632
"getChildRouteGuards",
633633
"getClosestRElement",
634-
"getClosestRouteInjector",
635634
"getClosureSafeProperty",
636635
"getComponentDef",
637636
"getComponentId",

packages/router/src/navigation_transition.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ import {UrlHandlingStrategy} from './url_handling_strategy';
8080
import {UrlSerializer, UrlTree} from './url_tree';
8181
import {Checks, getAllRouteGuards} from './utils/preactivation';
8282
import {CREATE_VIEW_TRANSITION} from './utils/view_transition';
83-
import {getClosestRouteInjector} from './utils/config';
8483
import {abortSignalToObservable} from './utils/abort_signal_to_observable';
8584

8685
/**
@@ -572,7 +571,10 @@ export class NavigationTransitions {
572571
restoredState,
573572
);
574573
this.events.next(navStart);
575-
const targetSnapshot = createEmptyState(this.rootComponentType).snapshot;
574+
const targetSnapshot = createEmptyState(
575+
this.rootComponentType,
576+
this.environmentInjector,
577+
).snapshot;
576578

577579
this.currentTransition = overallTransitionState = {
578580
...t,
@@ -623,17 +625,12 @@ export class NavigationTransitions {
623625

624626
this.currentTransition = overallTransitionState = {
625627
...t,
626-
guards: getAllRouteGuards(
627-
t.targetSnapshot!,
628-
t.currentSnapshot,
629-
this.rootContexts,
630-
this.environmentInjector,
631-
),
628+
guards: getAllRouteGuards(t.targetSnapshot!, t.currentSnapshot, this.rootContexts),
632629
};
633630
return overallTransitionState;
634631
}),
635632

636-
checkGuards(this.environmentInjector, (evt: Event) => this.events.next(evt)),
633+
checkGuards((evt: Event) => this.events.next(evt)),
637634

638635
switchMap((t) => {
639636
overallTransitionState.guardsResult = t.guardsResult;
@@ -674,7 +671,7 @@ export class NavigationTransitions {
674671

675672
let dataResolved = false;
676673
return of(t).pipe(
677-
resolveData(this.paramsInheritanceStrategy, this.environmentInjector),
674+
resolveData(this.paramsInheritanceStrategy),
678675
tap({
679676
next: () => {
680677
dataResolved = true;
@@ -708,7 +705,7 @@ export class NavigationTransitions {
708705
if (route.routeConfig?._loadedComponent) {
709706
route.component = route.routeConfig?._loadedComponent;
710707
} else if (route.routeConfig?.loadComponent) {
711-
const injector = getClosestRouteInjector(route) ?? this.environmentInjector;
708+
const injector = route._environmentInjector;
712709
loaders.push(
713710
this.configLoader
714711
.loadComponent(injector, route.routeConfig)

packages/router/src/operators/check_guards.ts

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import type {NavigationTransition} from '../navigation_transition';
3434
import type {ActivatedRouteSnapshot, RouterStateSnapshot} from '../router_state';
3535
import {UrlSegment, UrlSerializer} from '../url_tree';
3636
import {wrapIntoObservable} from '../utils/collection';
37-
import {getClosestRouteInjector} from '../utils/config';
3837
import {
3938
CanActivate,
4039
CanDeactivate,
@@ -54,7 +53,6 @@ import {prioritizedGuardValue} from './prioritized_guard_value';
5453
import {takeUntilAbort} from '../utils/abort_signal_to_observable';
5554

5655
export function checkGuards(
57-
injector: EnvironmentInjector,
5856
forwardEvent?: (evt: Event) => void,
5957
): MonoTypeOperatorFunction<NavigationTransition> {
6058
return mergeMap((t) => {
@@ -67,15 +65,10 @@ export function checkGuards(
6765
return of({...t, guardsResult: true});
6866
}
6967

70-
return runCanDeactivateChecks(
71-
canDeactivateChecks,
72-
targetSnapshot!,
73-
currentSnapshot,
74-
injector,
75-
).pipe(
68+
return runCanDeactivateChecks(canDeactivateChecks, targetSnapshot!, currentSnapshot).pipe(
7669
mergeMap((canDeactivate) => {
7770
return canDeactivate && isBoolean(canDeactivate)
78-
? runCanActivateChecks(targetSnapshot!, canActivateChecks, injector, forwardEvent)
71+
? runCanActivateChecks(targetSnapshot!, canActivateChecks, forwardEvent)
7972
: of(canDeactivate);
8073
}),
8174
map((guardsResult) => ({...t, guardsResult})),
@@ -87,12 +80,9 @@ function runCanDeactivateChecks(
8780
checks: CanDeactivate[],
8881
futureRSS: RouterStateSnapshot,
8982
currRSS: RouterStateSnapshot,
90-
injector: EnvironmentInjector,
9183
) {
9284
return from(checks).pipe(
93-
mergeMap((check) =>
94-
runCanDeactivate(check.component, check.route, currRSS, futureRSS, injector),
95-
),
85+
mergeMap((check) => runCanDeactivate(check.component, check.route, currRSS, futureRSS)),
9686
first((result) => {
9787
return result !== true;
9888
}, true),
@@ -102,16 +92,15 @@ function runCanDeactivateChecks(
10292
function runCanActivateChecks(
10393
futureSnapshot: RouterStateSnapshot,
10494
checks: CanActivate[],
105-
injector: EnvironmentInjector,
10695
forwardEvent?: (evt: Event) => void,
10796
) {
10897
return from(checks).pipe(
10998
concatMap((check: CanActivate) => {
11099
return concat(
111100
fireChildActivationStart(check.route.parent, forwardEvent),
112101
fireActivationStart(check.route, forwardEvent),
113-
runCanActivateChild(futureSnapshot, check.path, injector),
114-
runCanActivate(futureSnapshot, check.route, injector),
102+
runCanActivateChild(futureSnapshot, check.path),
103+
runCanActivate(futureSnapshot, check.route),
115104
);
116105
}),
117106
first((result) => {
@@ -159,14 +148,13 @@ function fireChildActivationStart(
159148
function runCanActivate(
160149
futureRSS: RouterStateSnapshot,
161150
futureARS: ActivatedRouteSnapshot,
162-
injector: EnvironmentInjector,
163151
): Observable<GuardResult> {
164152
const canActivate = futureARS.routeConfig ? futureARS.routeConfig.canActivate : null;
165153
if (!canActivate || canActivate.length === 0) return of(true);
166154

167155
const canActivateObservables = canActivate.map((canActivate) => {
168156
return defer(() => {
169-
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
157+
const closestInjector = futureARS._environmentInjector;
170158
const guard = getTokenOrFunctionIdentity<CanActivate>(
171159
canActivate as ProviderToken<CanActivate>,
172160
closestInjector,
@@ -185,7 +173,6 @@ function runCanActivate(
185173
function runCanActivateChild(
186174
futureRSS: RouterStateSnapshot,
187175
path: ActivatedRouteSnapshot[],
188-
injector: EnvironmentInjector,
189176
): Observable<GuardResult> {
190177
const futureARS = path[path.length - 1];
191178

@@ -199,7 +186,7 @@ function runCanActivateChild(
199186
return defer(() => {
200187
const guardsMapped = d.guards.map(
201188
(canActivateChild: CanActivateChildFn | ProviderToken<unknown>) => {
202-
const closestInjector = getClosestRouteInjector(d.node) ?? injector;
189+
const closestInjector = d.node._environmentInjector;
203190
const guard = getTokenOrFunctionIdentity<{canActivateChild: CanActivateChildFn}>(
204191
canActivateChild,
205192
closestInjector,
@@ -223,12 +210,11 @@ function runCanDeactivate(
223210
currARS: ActivatedRouteSnapshot,
224211
currRSS: RouterStateSnapshot,
225212
futureRSS: RouterStateSnapshot,
226-
injector: EnvironmentInjector,
227213
): Observable<GuardResult> {
228214
const canDeactivate = currARS && currARS.routeConfig ? currARS.routeConfig.canDeactivate : null;
229215
if (!canDeactivate || canDeactivate.length === 0) return of(true);
230216
const canDeactivateObservables = canDeactivate.map((c: any) => {
231-
const closestInjector = getClosestRouteInjector(currARS) ?? injector;
217+
const closestInjector = currARS._environmentInjector;
232218
const guard = getTokenOrFunctionIdentity<any>(c, closestInjector);
233219
const guardVal = isCanDeactivate(guard)
234220
? guard.canDeactivate(component, currARS, currRSS, futureRSS)

packages/router/src/operators/resolve_data.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,13 @@ import {
2020
} from '../router_state';
2121
import {RouteTitleKey} from '../shared';
2222
import {getDataKeys, wrapIntoObservable} from '../utils/collection';
23-
import {getClosestRouteInjector} from '../utils/config';
2423
import {getTokenOrFunctionIdentity} from '../utils/preactivation';
2524
import {isEmptyError} from '../utils/type_guards';
2625
import {redirectingNavigationError} from '../navigation_canceling_error';
2726
import {DefaultUrlSerializer} from '../url_tree';
2827

2928
export function resolveData(
3029
paramsInheritanceStrategy: 'emptyOnly' | 'always',
31-
injector: EnvironmentInjector,
3230
): MonoTypeOperatorFunction<NavigationTransition> {
3331
return mergeMap((t) => {
3432
const {
@@ -57,7 +55,7 @@ export function resolveData(
5755
return from(routesNeedingDataUpdates).pipe(
5856
concatMap((route) => {
5957
if (routesWithResolversToRun.has(route)) {
60-
return runResolve(route, targetSnapshot!, paramsInheritanceStrategy, injector);
58+
return runResolve(route, targetSnapshot!, paramsInheritanceStrategy);
6159
} else {
6260
route.data = getInherited(route, route.parent, paramsInheritanceStrategy).resolve;
6361
return of(void 0);
@@ -82,7 +80,6 @@ function runResolve(
8280
futureARS: ActivatedRouteSnapshot,
8381
futureRSS: RouterStateSnapshot,
8482
paramsInheritanceStrategy: 'emptyOnly' | 'always',
85-
injector: EnvironmentInjector,
8683
) {
8784
const config = futureARS.routeConfig;
8885
const resolve = futureARS._resolve;
@@ -91,7 +88,7 @@ function runResolve(
9188
}
9289
return defer(() => {
9390
futureARS.data = getInherited(futureARS, futureARS.parent, paramsInheritanceStrategy).resolve;
94-
return resolveNode(resolve, futureARS, futureRSS, injector).pipe(
91+
return resolveNode(resolve, futureARS, futureRSS).pipe(
9592
map((resolvedData: any) => {
9693
futureARS._resolvedData = resolvedData;
9794
futureARS.data = {...futureARS.data, ...resolvedData};
@@ -105,7 +102,6 @@ function resolveNode(
105102
resolve: ResolveData,
106103
futureARS: ActivatedRouteSnapshot,
107104
futureRSS: RouterStateSnapshot,
108-
injector: EnvironmentInjector,
109105
): Observable<any> {
110106
const keys = getDataKeys(resolve);
111107
if (keys.length === 0) {
@@ -114,7 +110,7 @@ function resolveNode(
114110
const data: {[k: string | symbol]: any} = {};
115111
return from(keys).pipe(
116112
mergeMap((key) =>
117-
getResolver(resolve[key], futureARS, futureRSS, injector).pipe(
113+
getResolver(resolve[key], futureARS, futureRSS).pipe(
118114
first(),
119115
tap((value: any) => {
120116
if (value instanceof RedirectCommand) {
@@ -134,9 +130,8 @@ function getResolver(
134130
injectionToken: ProviderToken<any> | Function,
135131
futureARS: ActivatedRouteSnapshot,
136132
futureRSS: RouterStateSnapshot,
137-
injector: EnvironmentInjector,
138133
): Observable<any> {
139-
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
134+
const closestInjector = futureARS._environmentInjector;
140135
const resolver = getTokenOrFunctionIdentity(injectionToken, closestInjector);
141136
const resolverValue = resolver.resolve
142137
? resolver.resolve(futureARS, futureRSS)

packages/router/src/recognize.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ export class Recognizer {
128128
this.rootComponentType,
129129
null,
130130
{},
131+
this.injector,
131132
);
132133
try {
133134
const children = await this.processSegmentGroup(
@@ -357,6 +358,7 @@ export class Recognizer {
357358
route.component ?? route._loadedComponent ?? null,
358359
route,
359360
getResolve(route),
361+
injector,
360362
);
361363
const inherited = getInherited(currentSnapshot, parentRoute, this.paramsInheritanceStrategy);
362364
currentSnapshot.params = Object.freeze(inherited.params);
@@ -425,6 +427,7 @@ export class Recognizer {
425427
route.component ?? route._loadedComponent ?? null,
426428
route,
427429
getResolve(route),
430+
injector,
428431
);
429432
const inherited = getInherited(snapshot, parentRoute, this.paramsInheritanceStrategy);
430433
snapshot.params = Object.freeze(inherited.params);

packages/router/src/recognize_rxjs.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ export class Recognizer {
147147
this.rootComponentType,
148148
null,
149149
{},
150+
this.injector,
150151
);
151152
return this.processSegmentGroup(
152153
this.injector,
@@ -385,6 +386,7 @@ export class Recognizer {
385386
route.component ?? route._loadedComponent ?? null,
386387
route,
387388
getResolve(route),
389+
injector,
388390
);
389391
const inherited = getInherited(currentSnapshot, parentRoute, this.paramsInheritanceStrategy);
390392
currentSnapshot.params = Object.freeze(inherited.params);
@@ -452,6 +454,7 @@ export class Recognizer {
452454
route.component ?? route._loadedComponent ?? null,
453455
route,
454456
getResolve(route),
457+
injector,
455458
);
456459
const inherited = getInherited(snapshot, parentRoute, this.paramsInheritanceStrategy);
457460
snapshot.params = Object.freeze(inherited.params);

packages/router/src/router_outlet_context.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {ComponentRef, EnvironmentInjector, Injectable} from '@angular/core';
1010

1111
import type {RouterOutletContract} from './directives/router_outlet';
1212
import {ActivatedRoute} from './router_state';
13-
import {getClosestRouteInjector} from './utils/config';
1413

1514
/**
1615
* Store contextual information about a `RouterOutlet`
@@ -23,7 +22,7 @@ export class OutletContext {
2322
children: ChildrenOutletContexts;
2423
attachRef: ComponentRef<any> | null = null;
2524
get injector(): EnvironmentInjector {
26-
return getClosestRouteInjector(this.route?.snapshot) ?? this.rootInjector;
25+
return this.route?.snapshot._environmentInjector ?? this.rootInjector;
2726
}
2827

2928
constructor(private readonly rootInjector: EnvironmentInjector) {

packages/router/src/router_state.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import {Type} from '@angular/core';
9+
import {EnvironmentInjector, Type} from '@angular/core';
1010
import {BehaviorSubject, Observable, of} from 'rxjs';
1111
import {map} from 'rxjs/operators';
1212

@@ -63,8 +63,11 @@ export class RouterState extends Tree<ActivatedRoute> {
6363
}
6464
}
6565

66-
export function createEmptyState(rootComponent: Type<any> | null): RouterState {
67-
const snapshot = createEmptyStateSnapshot(rootComponent);
66+
export function createEmptyState(
67+
rootComponent: Type<any> | null,
68+
injector: EnvironmentInjector,
69+
): RouterState {
70+
const snapshot = createEmptyStateSnapshot(rootComponent, injector);
6871
const emptyUrl = new BehaviorSubject([new UrlSegment('', {})]);
6972
const emptyParams = new BehaviorSubject({});
7073
const emptyData = new BehaviorSubject({});
@@ -84,7 +87,10 @@ export function createEmptyState(rootComponent: Type<any> | null): RouterState {
8487
return new RouterState(new TreeNode<ActivatedRoute>(activated, []), snapshot);
8588
}
8689

87-
export function createEmptyStateSnapshot(rootComponent: Type<any> | null): RouterStateSnapshot {
90+
export function createEmptyStateSnapshot(
91+
rootComponent: Type<any> | null,
92+
injector: EnvironmentInjector,
93+
): RouterStateSnapshot {
8894
const emptyParams = {};
8995
const emptyData = {};
9096
const emptyQueryParams = {};
@@ -99,6 +105,7 @@ export function createEmptyStateSnapshot(rootComponent: Type<any> | null): Route
99105
rootComponent,
100106
null,
101107
{},
108+
injector,
102109
);
103110
return new RouterStateSnapshot('', new TreeNode<ActivatedRouteSnapshot>(activated, []));
104111
}
@@ -332,6 +339,8 @@ export class ActivatedRouteSnapshot {
332339
_paramMap?: ParamMap;
333340
/** @internal */
334341
_queryParamMap?: ParamMap;
342+
/** @internal */
343+
readonly _environmentInjector: EnvironmentInjector;
335344

336345
/** The resolved route title */
337346
get title(): string | undefined {
@@ -376,9 +385,11 @@ export class ActivatedRouteSnapshot {
376385
public component: Type<any> | null,
377386
routeConfig: Route | null,
378387
resolve: ResolveData,
388+
environmentInjector: EnvironmentInjector,
379389
) {
380390
this.routeConfig = routeConfig;
381391
this._resolve = resolve;
392+
this._environmentInjector = environmentInjector;
382393
}
383394

384395
/** The root of the router state */

packages/router/src/statemanager/state_manager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import {Location} from '@angular/common';
10-
import {inject, Injectable} from '@angular/core';
10+
import {EnvironmentInjector, inject, Injectable} from '@angular/core';
1111
import {SubscriptionLike} from 'rxjs';
1212

1313
import {
@@ -104,7 +104,7 @@ export abstract class StateManager {
104104
}
105105
}
106106

107-
protected routerState = createEmptyState(null);
107+
protected routerState = createEmptyState(null, inject(EnvironmentInjector));
108108

109109
/** Returns the current RouterState. */
110110
getRouterState(): RouterState {

0 commit comments

Comments
 (0)