Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -633,7 +633,6 @@
"getCanActivateChild",
"getChildRouteGuards",
"getClosestRElement",
"getClosestRouteInjector",
"getClosureSafeProperty",
"getComponentDef",
"getComponentId",
Expand Down
12 changes: 7 additions & 5 deletions packages/router/src/navigation_transition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ import {UrlHandlingStrategy} from './url_handling_strategy';
import {UrlSerializer, UrlTree} from './url_tree';
import {Checks, getAllRouteGuards} from './utils/preactivation';
import {CREATE_VIEW_TRANSITION} from './utils/view_transition';
import {getClosestRouteInjector} from './utils/config';
import {abortSignalToObservable} from './utils/abort_signal_to_observable';

/**
Expand Down Expand Up @@ -572,7 +571,10 @@ export class NavigationTransitions {
restoredState,
);
this.events.next(navStart);
const targetSnapshot = createEmptyState(this.rootComponentType).snapshot;
const targetSnapshot = createEmptyState(
this.rootComponentType,
this.environmentInjector,
).snapshot;

this.currentTransition = overallTransitionState = {
...t,
Expand Down Expand Up @@ -628,7 +630,7 @@ export class NavigationTransitions {
return overallTransitionState;
}),

checkGuards(this.environmentInjector, (evt: Event) => this.events.next(evt)),
checkGuards((evt: Event) => this.events.next(evt)),

switchMap((t) => {
overallTransitionState.guardsResult = t.guardsResult;
Expand Down Expand Up @@ -669,7 +671,7 @@ export class NavigationTransitions {

let dataResolved = false;
return of(t).pipe(
resolveData(this.paramsInheritanceStrategy, this.environmentInjector),
resolveData(this.paramsInheritanceStrategy),
tap({
next: () => {
dataResolved = true;
Expand Down Expand Up @@ -703,7 +705,7 @@ export class NavigationTransitions {
if (route.routeConfig?._loadedComponent) {
route.component = route.routeConfig?._loadedComponent;
} else if (route.routeConfig?.loadComponent) {
const injector = getClosestRouteInjector(route) ?? this.environmentInjector;
const injector = route._environmentInjector;
loaders.push(
this.configLoader
.loadComponent(injector, route.routeConfig)
Expand Down
30 changes: 8 additions & 22 deletions packages/router/src/operators/check_guards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import type {NavigationTransition} from '../navigation_transition';
import type {ActivatedRouteSnapshot, RouterStateSnapshot} from '../router_state';
import {UrlSegment, UrlSerializer} from '../url_tree';
import {wrapIntoObservable} from '../utils/collection';
import {getClosestRouteInjector} from '../utils/config';
import {
CanActivate,
CanDeactivate,
Expand All @@ -54,7 +53,6 @@ import {prioritizedGuardValue} from './prioritized_guard_value';
import {takeUntilAbort} from '../utils/abort_signal_to_observable';

export function checkGuards(
injector: EnvironmentInjector,
forwardEvent?: (evt: Event) => void,
): MonoTypeOperatorFunction<NavigationTransition> {
return mergeMap((t) => {
Expand All @@ -67,15 +65,10 @@ export function checkGuards(
return of({...t, guardsResult: true});
}

return runCanDeactivateChecks(
canDeactivateChecks,
targetSnapshot!,
currentSnapshot,
injector,
).pipe(
return runCanDeactivateChecks(canDeactivateChecks, targetSnapshot!, currentSnapshot).pipe(
mergeMap((canDeactivate) => {
return canDeactivate && isBoolean(canDeactivate)
? runCanActivateChecks(targetSnapshot!, canActivateChecks, injector, forwardEvent)
? runCanActivateChecks(targetSnapshot!, canActivateChecks, forwardEvent)
: of(canDeactivate);
}),
map((guardsResult) => ({...t, guardsResult})),
Expand All @@ -87,12 +80,9 @@ function runCanDeactivateChecks(
checks: CanDeactivate[],
futureRSS: RouterStateSnapshot,
currRSS: RouterStateSnapshot,
injector: EnvironmentInjector,
) {
return from(checks).pipe(
mergeMap((check) =>
runCanDeactivate(check.component, check.route, currRSS, futureRSS, injector),
),
mergeMap((check) => runCanDeactivate(check.component, check.route, currRSS, futureRSS)),
first((result) => {
return result !== true;
}, true),
Expand All @@ -102,16 +92,15 @@ function runCanDeactivateChecks(
function runCanActivateChecks(
futureSnapshot: RouterStateSnapshot,
checks: CanActivate[],
injector: EnvironmentInjector,
forwardEvent?: (evt: Event) => void,
) {
return from(checks).pipe(
concatMap((check: CanActivate) => {
return concat(
fireChildActivationStart(check.route.parent, forwardEvent),
fireActivationStart(check.route, forwardEvent),
runCanActivateChild(futureSnapshot, check.path, injector),
runCanActivate(futureSnapshot, check.route, injector),
runCanActivateChild(futureSnapshot, check.path),
runCanActivate(futureSnapshot, check.route),
);
}),
first((result) => {
Expand Down Expand Up @@ -159,14 +148,13 @@ function fireChildActivationStart(
function runCanActivate(
futureRSS: RouterStateSnapshot,
futureARS: ActivatedRouteSnapshot,
injector: EnvironmentInjector,
): Observable<GuardResult> {
const canActivate = futureARS.routeConfig ? futureARS.routeConfig.canActivate : null;
if (!canActivate || canActivate.length === 0) return of(true);

const canActivateObservables = canActivate.map((canActivate) => {
return defer(() => {
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
const closestInjector = futureARS._environmentInjector;
const guard = getTokenOrFunctionIdentity<CanActivate>(
canActivate as ProviderToken<CanActivate>,
closestInjector,
Expand All @@ -185,7 +173,6 @@ function runCanActivate(
function runCanActivateChild(
futureRSS: RouterStateSnapshot,
path: ActivatedRouteSnapshot[],
injector: EnvironmentInjector,
): Observable<GuardResult> {
const futureARS = path[path.length - 1];

Expand All @@ -199,7 +186,7 @@ function runCanActivateChild(
return defer(() => {
const guardsMapped = d.guards.map(
(canActivateChild: CanActivateChildFn | ProviderToken<unknown>) => {
const closestInjector = getClosestRouteInjector(d.node) ?? injector;
const closestInjector = d.node._environmentInjector;
const guard = getTokenOrFunctionIdentity<{canActivateChild: CanActivateChildFn}>(
canActivateChild,
closestInjector,
Expand All @@ -223,12 +210,11 @@ function runCanDeactivate(
currARS: ActivatedRouteSnapshot,
currRSS: RouterStateSnapshot,
futureRSS: RouterStateSnapshot,
injector: EnvironmentInjector,
): Observable<GuardResult> {
const canDeactivate = currARS && currARS.routeConfig ? currARS.routeConfig.canDeactivate : null;
if (!canDeactivate || canDeactivate.length === 0) return of(true);
const canDeactivateObservables = canDeactivate.map((c: any) => {
const closestInjector = getClosestRouteInjector(currARS) ?? injector;
const closestInjector = currARS._environmentInjector;
const guard = getTokenOrFunctionIdentity<any>(c, closestInjector);
const guardVal = isCanDeactivate(guard)
? guard.canDeactivate(component, currARS, currRSS, futureRSS)
Expand Down
13 changes: 4 additions & 9 deletions packages/router/src/operators/resolve_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@ import {
} from '../router_state';
import {RouteTitleKey} from '../shared';
import {getDataKeys, wrapIntoObservable} from '../utils/collection';
import {getClosestRouteInjector} from '../utils/config';
import {getTokenOrFunctionIdentity} from '../utils/preactivation';
import {isEmptyError} from '../utils/type_guards';
import {redirectingNavigationError} from '../navigation_canceling_error';
import {DefaultUrlSerializer} from '../url_tree';

export function resolveData(
paramsInheritanceStrategy: 'emptyOnly' | 'always',
injector: EnvironmentInjector,
): MonoTypeOperatorFunction<NavigationTransition> {
return mergeMap((t) => {
const {
Expand Down Expand Up @@ -57,7 +55,7 @@ export function resolveData(
return from(routesNeedingDataUpdates).pipe(
concatMap((route) => {
if (routesWithResolversToRun.has(route)) {
return runResolve(route, targetSnapshot!, paramsInheritanceStrategy, injector);
return runResolve(route, targetSnapshot!, paramsInheritanceStrategy);
} else {
route.data = getInherited(route, route.parent, paramsInheritanceStrategy).resolve;
return of(void 0);
Expand All @@ -82,7 +80,6 @@ function runResolve(
futureARS: ActivatedRouteSnapshot,
futureRSS: RouterStateSnapshot,
paramsInheritanceStrategy: 'emptyOnly' | 'always',
injector: EnvironmentInjector,
) {
const config = futureARS.routeConfig;
const resolve = futureARS._resolve;
Expand All @@ -91,7 +88,7 @@ function runResolve(
}
return defer(() => {
futureARS.data = getInherited(futureARS, futureARS.parent, paramsInheritanceStrategy).resolve;
return resolveNode(resolve, futureARS, futureRSS, injector).pipe(
return resolveNode(resolve, futureARS, futureRSS).pipe(
map((resolvedData: any) => {
futureARS._resolvedData = resolvedData;
futureARS.data = {...futureARS.data, ...resolvedData};
Expand All @@ -105,7 +102,6 @@ function resolveNode(
resolve: ResolveData,
futureARS: ActivatedRouteSnapshot,
futureRSS: RouterStateSnapshot,
injector: EnvironmentInjector,
): Observable<any> {
const keys = getDataKeys(resolve);
if (keys.length === 0) {
Expand All @@ -114,7 +110,7 @@ function resolveNode(
const data: {[k: string | symbol]: any} = {};
return from(keys).pipe(
mergeMap((key) =>
getResolver(resolve[key], futureARS, futureRSS, injector).pipe(
getResolver(resolve[key], futureARS, futureRSS).pipe(
first(),
tap((value: any) => {
if (value instanceof RedirectCommand) {
Expand All @@ -134,9 +130,8 @@ function getResolver(
injectionToken: ProviderToken<any> | Function,
futureARS: ActivatedRouteSnapshot,
futureRSS: RouterStateSnapshot,
injector: EnvironmentInjector,
): Observable<any> {
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
const closestInjector = futureARS._environmentInjector;
const resolver = getTokenOrFunctionIdentity(injectionToken, closestInjector);
const resolverValue = resolver.resolve
? resolver.resolve(futureARS, futureRSS)
Expand Down
3 changes: 3 additions & 0 deletions packages/router/src/recognize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export class Recognizer {
this.rootComponentType,
null,
{},
this.injector,
);
try {
const children = await this.processSegmentGroup(
Expand Down Expand Up @@ -357,6 +358,7 @@ export class Recognizer {
route.component ?? route._loadedComponent ?? null,
route,
getResolve(route),
injector,
);
const inherited = getInherited(currentSnapshot, parentRoute, this.paramsInheritanceStrategy);
currentSnapshot.params = Object.freeze(inherited.params);
Expand Down Expand Up @@ -425,6 +427,7 @@ export class Recognizer {
route.component ?? route._loadedComponent ?? null,
route,
getResolve(route),
injector,
);
const inherited = getInherited(snapshot, parentRoute, this.paramsInheritanceStrategy);
snapshot.params = Object.freeze(inherited.params);
Expand Down
3 changes: 3 additions & 0 deletions packages/router/src/recognize_rxjs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export class Recognizer {
this.rootComponentType,
null,
{},
this.injector,
);
return this.processSegmentGroup(
this.injector,
Expand Down Expand Up @@ -385,6 +386,7 @@ export class Recognizer {
route.component ?? route._loadedComponent ?? null,
route,
getResolve(route),
injector,
);
const inherited = getInherited(currentSnapshot, parentRoute, this.paramsInheritanceStrategy);
currentSnapshot.params = Object.freeze(inherited.params);
Expand Down Expand Up @@ -452,6 +454,7 @@ export class Recognizer {
route.component ?? route._loadedComponent ?? null,
route,
getResolve(route),
injector,
);
const inherited = getInherited(snapshot, parentRoute, this.paramsInheritanceStrategy);
snapshot.params = Object.freeze(inherited.params);
Expand Down
3 changes: 1 addition & 2 deletions packages/router/src/router_outlet_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {ComponentRef, EnvironmentInjector, Injectable} from '@angular/core';

import type {RouterOutletContract} from './directives/router_outlet';
import {ActivatedRoute} from './router_state';
import {getClosestRouteInjector} from './utils/config';

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

constructor(private readonly rootInjector: EnvironmentInjector) {
Expand Down
19 changes: 15 additions & 4 deletions packages/router/src/router_state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {Type} from '@angular/core';
import {EnvironmentInjector, Type} from '@angular/core';
import {BehaviorSubject, Observable, of} from 'rxjs';
import {map} from 'rxjs/operators';

Expand Down Expand Up @@ -63,8 +63,11 @@ export class RouterState extends Tree<ActivatedRoute> {
}
}

export function createEmptyState(rootComponent: Type<any> | null): RouterState {
const snapshot = createEmptyStateSnapshot(rootComponent);
export function createEmptyState(
rootComponent: Type<any> | null,
injector: EnvironmentInjector,
): RouterState {
const snapshot = createEmptyStateSnapshot(rootComponent, injector);
const emptyUrl = new BehaviorSubject([new UrlSegment('', {})]);
const emptyParams = new BehaviorSubject({});
const emptyData = new BehaviorSubject({});
Expand All @@ -84,7 +87,10 @@ export function createEmptyState(rootComponent: Type<any> | null): RouterState {
return new RouterState(new TreeNode<ActivatedRoute>(activated, []), snapshot);
}

export function createEmptyStateSnapshot(rootComponent: Type<any> | null): RouterStateSnapshot {
export function createEmptyStateSnapshot(
rootComponent: Type<any> | null,
injector: EnvironmentInjector,
): RouterStateSnapshot {
const emptyParams = {};
const emptyData = {};
const emptyQueryParams = {};
Expand All @@ -99,6 +105,7 @@ export function createEmptyStateSnapshot(rootComponent: Type<any> | null): Route
rootComponent,
null,
{},
injector,
);
return new RouterStateSnapshot('', new TreeNode<ActivatedRouteSnapshot>(activated, []));
}
Expand Down Expand Up @@ -330,6 +337,8 @@ export class ActivatedRouteSnapshot {
_paramMap?: ParamMap;
/** @internal */
_queryParamMap?: ParamMap;
/** @internal */
readonly _environmentInjector: EnvironmentInjector;

/** The resolved route title */
get title(): string | undefined {
Expand Down Expand Up @@ -374,9 +383,11 @@ export class ActivatedRouteSnapshot {
public component: Type<any> | null,
routeConfig: Route | null,
resolve: ResolveData,
environmentInjector: EnvironmentInjector,
) {
this.routeConfig = routeConfig;
this._resolve = resolve;
this._environmentInjector = environmentInjector;
}

/** The root of the router state */
Expand Down
4 changes: 2 additions & 2 deletions packages/router/src/statemanager/state_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import {Location} from '@angular/common';
import {inject, Injectable} from '@angular/core';
import {EnvironmentInjector, inject, Injectable} from '@angular/core';
import {SubscriptionLike} from 'rxjs';

import {
Expand Down Expand Up @@ -104,7 +104,7 @@ export abstract class StateManager {
}
}

protected routerState = createEmptyState(null);
protected routerState = createEmptyState(null, inject(EnvironmentInjector));

/** Returns the current RouterState. */
getRouterState(): RouterState {
Expand Down
Loading