diff --git a/goldens/public-api/router/index.md b/goldens/public-api/router/index.md index fd15066e36b..9af1ac5f196 100644 --- a/goldens/public-api/router/index.md +++ b/goldens/public-api/router/index.md @@ -357,6 +357,8 @@ export class OutletContext { // (undocumented) children: ChildrenOutletContexts; // (undocumented) + injector: EnvironmentInjector | null; + // (undocumented) outlet: RouterOutletContract | null; // (undocumented) resolver: ComponentFactoryResolver | null; @@ -645,7 +647,7 @@ export class RouterModule { // @public export class RouterOutlet implements OnDestroy, OnInit, RouterOutletContract { - constructor(parentContexts: ChildrenOutletContexts, location: ViewContainerRef, resolver: ComponentFactoryResolver, name: string, changeDetector: ChangeDetectorRef); + constructor(parentContexts: ChildrenOutletContexts, location: ViewContainerRef, name: string, changeDetector: ChangeDetectorRef, environmentInjector: EnvironmentInjector); // (undocumented) get activatedRoute(): ActivatedRoute; // (undocumented) @@ -653,7 +655,7 @@ export class RouterOutlet implements OnDestroy, OnInit, RouterOutletContract { // (undocumented) activateEvents: EventEmitter; // (undocumented) - activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null): void; + activateWith(activatedRoute: ActivatedRoute, resolverOrInjector?: ComponentFactoryResolver | EnvironmentInjector | null): void; attach(ref: ComponentRef, activatedRoute: ActivatedRoute): void; attachEvents: EventEmitter; // (undocumented) @@ -673,7 +675,7 @@ export class RouterOutlet implements OnDestroy, OnInit, RouterOutletContract { // (undocumented) static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) - static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵfac: i0.ɵɵFactoryDeclaration; } // @public @@ -681,6 +683,7 @@ export interface RouterOutletContract { activatedRoute: ActivatedRoute | null; activatedRouteData: Data; activateEvents?: EventEmitter; + activateWith(activatedRoute: ActivatedRoute, environmnetInjector: EnvironmentInjector | null): void; activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null): void; attach(ref: ComponentRef, activatedRoute: ActivatedRoute): void; attachEvents?: EventEmitter; diff --git a/packages/router/src/directives/router_outlet.ts b/packages/router/src/directives/router_outlet.ts index 20977befdb2..f6795c21953 100644 --- a/packages/router/src/directives/router_outlet.ts +++ b/packages/router/src/directives/router_outlet.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {Attribute, ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, OnInit, Output, ViewContainerRef} from '@angular/core'; +import {Attribute, ChangeDetectorRef, ComponentFactoryResolver, ComponentRef, Directive, EnvironmentInjector, EventEmitter, Injector, OnDestroy, OnInit, Output, ViewContainerRef,} from '@angular/core'; import {Data} from '../models'; import {ChildrenOutletContexts} from '../router_outlet_context'; @@ -47,6 +47,10 @@ export interface RouterOutletContract { */ activatedRoute: ActivatedRoute|null; + /** + * Called by the `Router` when the outlet should activate (create a component). + */ + activateWith(activatedRoute: ActivatedRoute, environmnetInjector: EnvironmentInjector|null): void; /** * Called by the `Router` when the outlet should activate (create a component). */ @@ -168,8 +172,8 @@ export class RouterOutlet implements OnDestroy, OnInit, RouterOutletContract { constructor( private parentContexts: ChildrenOutletContexts, private location: ViewContainerRef, - private resolver: ComponentFactoryResolver, @Attribute('name') name: string, - private changeDetector: ChangeDetectorRef) { + @Attribute('name') name: string, private changeDetector: ChangeDetectorRef, + private environmentInjector: EnvironmentInjector) { this.name = name || PRIMARY_OUTLET; parentContexts.onChildOutletCreated(this.name, this); } @@ -191,7 +195,7 @@ export class RouterOutlet implements OnDestroy, OnInit, RouterOutletContract { this.attach(context.attachRef, context.route); } else { // otherwise the component defined in the configuration is created - this.activateWith(context.route, context.resolver || null); + this.activateWith(context.route, context.injector); } } } @@ -255,18 +259,27 @@ export class RouterOutlet implements OnDestroy, OnInit, RouterOutletContract { } } - activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) { + activateWith( + activatedRoute: ActivatedRoute, + resolverOrInjector?: ComponentFactoryResolver|EnvironmentInjector|null) { if (this.isActivated) { throw new Error('Cannot activate an already activated outlet'); } this._activatedRoute = activatedRoute; + const location = this.location; const snapshot = activatedRoute._futureSnapshot; const component = snapshot.routeConfig!.component; - resolver = resolver || this.resolver; - const factory = resolver.resolveComponentFactory(component); const childContexts = this.parentContexts.getOrCreateContext(this.name).children; - const injector = new OutletInjector(activatedRoute, childContexts, this.location.injector); - this.activated = this.location.createComponent(factory, this.location.length, injector); + const injector = new OutletInjector(activatedRoute, childContexts, location.injector); + + if (resolverOrInjector && isComponentFactoryResolver(resolverOrInjector)) { + const factory = resolverOrInjector.resolveComponentFactory(component); + this.activated = location.createComponent(factory, location.length, injector); + } else { + const environmentInjector = resolverOrInjector ?? this.environmentInjector; + this.activated = location.createComponent( + component, {index: location.length, injector, environmentInjector}); + } // Calling `markForCheck` to make sure we will run the change detection when the // `RouterOutlet` is inside a `ChangeDetectionStrategy.OnPush` component. this.changeDetector.markForCheck(); @@ -291,3 +304,7 @@ class OutletInjector implements Injector { return this.parent.get(token, notFoundValue); } } + +function isComponentFactoryResolver(item: any): item is ComponentFactoryResolver { + return !!item.resolveComponentFactory; +} diff --git a/packages/router/src/operators/activate_routes.ts b/packages/router/src/operators/activate_routes.ts index a014e001c20..7f173ec6d25 100644 --- a/packages/router/src/operators/activate_routes.ts +++ b/packages/router/src/operators/activate_routes.ts @@ -198,10 +198,11 @@ export class ActivateRoutes { context.attachRef = null; context.route = future; context.resolver = cmpFactoryResolver; + context.injector = injector; if (context.outlet) { // Activate the outlet when it has already been instantiated // Otherwise it will get activated from its `ngOnInit` when instantiated - context.outlet.activateWith(future, cmpFactoryResolver); + context.outlet.activateWith(future, context.injector); } this.activateChildRoutes(futureNode, null, context.children); diff --git a/packages/router/src/router_outlet_context.ts b/packages/router/src/router_outlet_context.ts index fc5974f8e5d..598baeeaa86 100644 --- a/packages/router/src/router_outlet_context.ts +++ b/packages/router/src/router_outlet_context.ts @@ -21,6 +21,7 @@ export class OutletContext { outlet: RouterOutletContract|null = null; route: ActivatedRoute|null = null; resolver: ComponentFactoryResolver|null = null; + injector: EnvironmentInjector|null = null; children = new ChildrenOutletContexts(); attachRef: ComponentRef|null = null; }