refactor(router): don't run the change detection every time an outlet is activated
This commit is contained in:
committed by
Matias Niemelä
parent
44d48d9d7a
commit
198edb3109
@@ -6,8 +6,8 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Attribute, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, Output, ReflectiveInjector, ResolvedReflectiveProvider, ViewContainerRef} from '@angular/core';
|
||||
import {RouterOutletMap} from '../router_outlet_map';
|
||||
import {Attribute, ComponentFactoryResolver, ComponentRef, Directive, EventEmitter, Injector, OnDestroy, OnInit, Output, ViewContainerRef} from '@angular/core';
|
||||
import {ChildrenOutletContexts} from '../router_outlet_context';
|
||||
import {ActivatedRoute} from '../router_state';
|
||||
import {PRIMARY_OUTLET} from '../shared';
|
||||
|
||||
@@ -36,23 +36,39 @@ import {PRIMARY_OUTLET} from '../shared';
|
||||
* @stable
|
||||
*/
|
||||
@Directive({selector: 'router-outlet'})
|
||||
export class RouterOutlet implements OnDestroy {
|
||||
export class RouterOutlet implements OnDestroy, OnInit {
|
||||
private activated: ComponentRef<any>|null = null;
|
||||
private _activatedRoute: ActivatedRoute|null = null;
|
||||
private _outletName: string;
|
||||
public outletMap: RouterOutletMap;
|
||||
private name: string;
|
||||
|
||||
@Output('activate') activateEvents = new EventEmitter<any>();
|
||||
@Output('deactivate') deactivateEvents = new EventEmitter<any>();
|
||||
|
||||
constructor(
|
||||
private parentOutletMap: RouterOutletMap, private location: ViewContainerRef,
|
||||
private parentContexts: ChildrenOutletContexts, private location: ViewContainerRef,
|
||||
private resolver: ComponentFactoryResolver, @Attribute('name') name: string) {
|
||||
this._outletName = name || PRIMARY_OUTLET;
|
||||
parentOutletMap.registerOutlet(this._outletName, this);
|
||||
this.name = name || PRIMARY_OUTLET;
|
||||
parentContexts.onChildOutletCreated(this.name, this);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void { this.parentOutletMap.removeOutlet(this._outletName); }
|
||||
ngOnDestroy(): void { this.parentContexts.onChildOutletDestroyed(this.name); }
|
||||
|
||||
ngOnInit(): void {
|
||||
if (!this.activated) {
|
||||
// If the outlet was not instantiated at the time the route got activated we need to populate
|
||||
// the outlet when it is initialized.
|
||||
const context = this.parentContexts.getContext(this.name);
|
||||
if (context && context.route) {
|
||||
if (context.attachRef) {
|
||||
// `attachRef` is populated when there is an existing component to mount
|
||||
this.attach(context.attachRef, context.route);
|
||||
} else {
|
||||
// otherwise the component defined in the configuration is created
|
||||
this.activateWith(context.route, context.resolver || null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated since v4 **/
|
||||
get locationInjector(): Injector { return this.location.injector; }
|
||||
@@ -102,65 +118,34 @@ export class RouterOutlet implements OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated since v4, use {@link #activateWith} */
|
||||
activate(
|
||||
activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver, injector: Injector,
|
||||
providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap): void {
|
||||
activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null) {
|
||||
if (this.isActivated) {
|
||||
throw new Error('Cannot activate an already activated outlet');
|
||||
}
|
||||
|
||||
this.outletMap = outletMap;
|
||||
this._activatedRoute = activatedRoute;
|
||||
|
||||
const snapshot = activatedRoute._futureSnapshot;
|
||||
const component: any = <any>snapshot._routeConfig !.component;
|
||||
const factory = resolver.resolveComponentFactory(component) !;
|
||||
|
||||
const inj = ReflectiveInjector.fromResolvedProviders(providers, injector);
|
||||
|
||||
this.activated = this.location.createComponent(factory, this.location.length, inj, []);
|
||||
this.activated.changeDetectorRef.detectChanges();
|
||||
|
||||
this.activateEvents.emit(this.activated.instance);
|
||||
}
|
||||
|
||||
activateWith(
|
||||
activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver|null,
|
||||
outletMap: RouterOutletMap) {
|
||||
if (this.isActivated) {
|
||||
throw new Error('Cannot activate an already activated outlet');
|
||||
}
|
||||
|
||||
this.outletMap = outletMap;
|
||||
this._activatedRoute = activatedRoute;
|
||||
|
||||
const snapshot = activatedRoute._futureSnapshot;
|
||||
const component = <any>snapshot._routeConfig !.component;
|
||||
|
||||
resolver = resolver || this.resolver;
|
||||
const factory = resolver.resolveComponentFactory(component);
|
||||
|
||||
const injector = new OutletInjector(activatedRoute, outletMap, this.location.injector);
|
||||
|
||||
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);
|
||||
this.activated.changeDetectorRef.detectChanges();
|
||||
|
||||
this.activateEvents.emit(this.activated.instance);
|
||||
}
|
||||
}
|
||||
|
||||
class OutletInjector implements Injector {
|
||||
constructor(
|
||||
private route: ActivatedRoute, private map: RouterOutletMap, private parent: Injector) {}
|
||||
private route: ActivatedRoute, private childContexts: ChildrenOutletContexts,
|
||||
private parent: Injector) {}
|
||||
|
||||
get(token: any, notFoundValue?: any): any {
|
||||
if (token === ActivatedRoute) {
|
||||
return this.route;
|
||||
}
|
||||
|
||||
if (token === RouterOutletMap) {
|
||||
return this.map;
|
||||
if (token === ChildrenOutletContexts) {
|
||||
return this.childContexts;
|
||||
}
|
||||
|
||||
return this.parent.get(token, notFoundValue);
|
||||
|
||||
@@ -17,7 +17,7 @@ export {DetachedRouteHandle, RouteReuseStrategy} from './route_reuse_strategy';
|
||||
export {NavigationExtras, Router} from './router';
|
||||
export {ROUTES} from './router_config_loader';
|
||||
export {ExtraOptions, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, RouterModule, provideRoutes} from './router_module';
|
||||
export {RouterOutletMap} from './router_outlet_map';
|
||||
export {ChildrenOutletContexts, OutletContext} from './router_outlet_context';
|
||||
export {NoPreloading, PreloadAllModules, PreloadingStrategy, RouterPreloader} from './router_preloader';
|
||||
export {ActivatedRoute, ActivatedRouteSnapshot, RouterState, RouterStateSnapshot} from './router_state';
|
||||
export {PRIMARY_OUTLET, ParamMap, Params, convertToParamMap} from './shared';
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import {ComponentRef} from '@angular/core';
|
||||
|
||||
import {OutletContext} from './router_outlet_context';
|
||||
import {ActivatedRoute, ActivatedRouteSnapshot} from './router_state';
|
||||
import {TreeNode} from './utils/tree';
|
||||
|
||||
@@ -23,6 +24,7 @@ export type DetachedRouteHandle = {};
|
||||
|
||||
/** @internal */
|
||||
export type DetachedRouteHandleInternal = {
|
||||
contexts: Map<string, OutletContext>,
|
||||
componentRef: ComponentRef<any>,
|
||||
route: TreeNode<ActivatedRoute>,
|
||||
};
|
||||
@@ -36,7 +38,11 @@ export abstract class RouteReuseStrategy {
|
||||
/** Determines if this route (and its subtree) should be detached to be reused later */
|
||||
abstract shouldDetach(route: ActivatedRouteSnapshot): boolean;
|
||||
|
||||
/** Stores the detached route */
|
||||
/**
|
||||
* Stores the detached route.
|
||||
*
|
||||
* Storing a `null` value should erase the previously stored value.
|
||||
*/
|
||||
abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle|null): void;
|
||||
|
||||
/** Determines if this route (and its subtree) should be reattached */
|
||||
|
||||
+102
-101
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ import {RouterOutlet} from './directives/router_outlet';
|
||||
import {RouteReuseStrategy} from './route_reuse_strategy';
|
||||
import {ErrorHandler, Router} from './router';
|
||||
import {ROUTES} from './router_config_loader';
|
||||
import {RouterOutletMap} from './router_outlet_map';
|
||||
import {ChildrenOutletContexts} from './router_outlet_context';
|
||||
import {NoPreloading, PreloadAllModules, PreloadingStrategy, RouterPreloader} from './router_preloader';
|
||||
import {ActivatedRoute} from './router_state';
|
||||
import {UrlHandlingStrategy} from './url_handling_strategy';
|
||||
@@ -51,12 +51,12 @@ export const ROUTER_PROVIDERS: Provider[] = [
|
||||
provide: Router,
|
||||
useFactory: setupRouter,
|
||||
deps: [
|
||||
ApplicationRef, UrlSerializer, RouterOutletMap, Location, Injector, NgModuleFactoryLoader,
|
||||
Compiler, ROUTES, ROUTER_CONFIGURATION, [UrlHandlingStrategy, new Optional()],
|
||||
[RouteReuseStrategy, new Optional()]
|
||||
ApplicationRef, UrlSerializer, ChildrenOutletContexts, Location, Injector,
|
||||
NgModuleFactoryLoader, Compiler, ROUTES, ROUTER_CONFIGURATION,
|
||||
[UrlHandlingStrategy, new Optional()], [RouteReuseStrategy, new Optional()]
|
||||
]
|
||||
},
|
||||
RouterOutletMap,
|
||||
ChildrenOutletContexts,
|
||||
{provide: ActivatedRoute, useFactory: rootRoute, deps: [Router]},
|
||||
{provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader},
|
||||
RouterPreloader,
|
||||
@@ -270,12 +270,12 @@ export interface ExtraOptions {
|
||||
}
|
||||
|
||||
export function setupRouter(
|
||||
ref: ApplicationRef, urlSerializer: UrlSerializer, outletMap: RouterOutletMap,
|
||||
ref: ApplicationRef, urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts,
|
||||
location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler,
|
||||
config: Route[][], opts: ExtraOptions = {}, urlHandlingStrategy?: UrlHandlingStrategy,
|
||||
routeReuseStrategy?: RouteReuseStrategy) {
|
||||
const router = new Router(
|
||||
null, urlSerializer, outletMap, location, injector, loader, compiler, flatten(config));
|
||||
null, urlSerializer, contexts, location, injector, loader, compiler, flatten(config));
|
||||
|
||||
if (urlHandlingStrategy) {
|
||||
router.urlHandlingStrategy = urlHandlingStrategy;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ComponentFactoryResolver, ComponentRef} from '@angular/core';
|
||||
|
||||
import {RouterOutlet} from './directives/router_outlet';
|
||||
import {ActivatedRoute} from './router_state';
|
||||
|
||||
|
||||
/**
|
||||
* Store contextual information about a {@link RouterOutlet}
|
||||
*
|
||||
* @stable
|
||||
*/
|
||||
export class OutletContext {
|
||||
outlet: RouterOutlet|null = null;
|
||||
route: ActivatedRoute|null = null;
|
||||
resolver: ComponentFactoryResolver|null = null;
|
||||
children = new ChildrenOutletContexts();
|
||||
attachRef: ComponentRef<any>|null = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store contextual information about the children (= nested) {@link RouterOutlet}
|
||||
*
|
||||
* @stable
|
||||
*/
|
||||
export class ChildrenOutletContexts {
|
||||
// contexts for child outlets, by name.
|
||||
private contexts = new Map<string, OutletContext>();
|
||||
|
||||
/** Called when a `RouterOutlet` directive is instantiated */
|
||||
onChildOutletCreated(childName: string, outlet: RouterOutlet): void {
|
||||
const context = this.getOrCreateContext(childName);
|
||||
context.outlet = outlet;
|
||||
this.contexts.set(childName, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a `RouterOutlet` directive is destroyed.
|
||||
* We need to keep the context as the outlet could be destroyed inside a NgIf and might be
|
||||
* re-created later.
|
||||
*/
|
||||
onChildOutletDestroyed(childName: string): void {
|
||||
const context = this.getContext(childName);
|
||||
if (context) {
|
||||
context.outlet = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the corresponding route is deactivated during navigation.
|
||||
* Because the component get destroyed, all children outlet are destroyed.
|
||||
*/
|
||||
onOutletDeactivated(): Map<string, OutletContext> {
|
||||
const contexts = this.contexts;
|
||||
this.contexts = new Map();
|
||||
return contexts;
|
||||
}
|
||||
|
||||
onOutletReAttached(contexts: Map<string, OutletContext>) { this.contexts = contexts; }
|
||||
|
||||
getOrCreateContext(childName: string): OutletContext {
|
||||
let context = this.getContext(childName);
|
||||
|
||||
if (!context) {
|
||||
context = new OutletContext();
|
||||
this.contexts.set(childName, context);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
getContext(childName: string): OutletContext|null { return this.contexts.get(childName) || null; }
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {RouterOutlet} from './directives/router_outlet';
|
||||
|
||||
/**
|
||||
* @whatItDoes Contains all the router outlets created in a component.
|
||||
*
|
||||
* @stable
|
||||
*/
|
||||
export class RouterOutletMap {
|
||||
/** @internal */
|
||||
_outlets: {[name: string]: RouterOutlet} = {};
|
||||
|
||||
/**
|
||||
* Adds an outlet to this map.
|
||||
*/
|
||||
registerOutlet(name: string, outlet: RouterOutlet): void { this._outlets[name] = outlet; }
|
||||
|
||||
/**
|
||||
* Removes an outlet from this map.
|
||||
*/
|
||||
removeOutlet(name: string): void { this._outlets[name] = undefined as any; }
|
||||
}
|
||||
@@ -120,8 +120,10 @@ describe('Integration', () => {
|
||||
router.resetConfig([{
|
||||
path: 'parent/:id',
|
||||
component: Parent,
|
||||
children:
|
||||
[{path: 'child1', component: Child1}, {path: 'child2', component: Child2}]
|
||||
children: [
|
||||
{path: 'child1', component: Child1},
|
||||
{path: 'child2', component: Child2},
|
||||
]
|
||||
}]);
|
||||
|
||||
router.navigateByUrl('/parent/1/child1');
|
||||
@@ -131,13 +133,18 @@ describe('Integration', () => {
|
||||
advance(fixture);
|
||||
|
||||
expect(location.path()).toEqual('/parent/2/child2');
|
||||
expect(log).toEqual([{id: '1'}, 'child1 destroy', {id: '2'}, 'child2 constructor']);
|
||||
expect(log).toEqual([
|
||||
{id: '1'},
|
||||
'child1 destroy',
|
||||
{id: '2'},
|
||||
'child2 constructor',
|
||||
]);
|
||||
})));
|
||||
|
||||
});
|
||||
|
||||
it('should execute navigations serialy',
|
||||
fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
||||
fakeAsync(inject([Router, Location], (router: Router) => {
|
||||
const fixture = createRoot(router, RootCmp);
|
||||
|
||||
router.resetConfig([
|
||||
@@ -202,7 +209,7 @@ describe('Integration', () => {
|
||||
|
||||
router.resetConfig([{
|
||||
path: 'child',
|
||||
component: LinkInNgIf,
|
||||
component: OutletInNgIf,
|
||||
children: [{path: 'simple', component: SimpleCmp}]
|
||||
}]);
|
||||
|
||||
@@ -212,10 +219,10 @@ describe('Integration', () => {
|
||||
expect(location.path()).toEqual('/child/simple');
|
||||
})));
|
||||
|
||||
it('should work when an outlet is in an ngIf (and is removed)', fakeAsync(() => {
|
||||
it('should work when an outlet is added/removed', fakeAsync(() => {
|
||||
@Component({
|
||||
selector: 'someRoot',
|
||||
template: `<div *ngIf="cond"><router-outlet></router-outlet></div>`
|
||||
template: `[<div *ngIf="cond"><router-outlet></router-outlet></div>]`
|
||||
})
|
||||
class RootCmpWithLink {
|
||||
cond: boolean = true;
|
||||
@@ -223,26 +230,25 @@ describe('Integration', () => {
|
||||
TestBed.configureTestingModule({declarations: [RootCmpWithLink]});
|
||||
|
||||
const router: Router = TestBed.get(Router);
|
||||
const location: Location = TestBed.get(Location);
|
||||
|
||||
const fixture = createRoot(router, RootCmpWithLink);
|
||||
|
||||
router.resetConfig(
|
||||
[{path: 'simple', component: SimpleCmp}, {path: 'blank', component: BlankCmp}]);
|
||||
router.resetConfig([
|
||||
{path: 'simple', component: SimpleCmp},
|
||||
{path: 'blank', component: BlankCmp},
|
||||
]);
|
||||
|
||||
router.navigateByUrl('/simple');
|
||||
advance(fixture);
|
||||
expect(location.path()).toEqual('/simple');
|
||||
expect(fixture.nativeElement).toHaveText('[simple]');
|
||||
|
||||
const instance = fixture.componentInstance;
|
||||
instance.cond = false;
|
||||
fixture.componentInstance.cond = false;
|
||||
advance(fixture);
|
||||
expect(fixture.nativeElement).toHaveText('[]');
|
||||
|
||||
let recordedError: any = null;
|
||||
router.navigateByUrl('/blank') !.catch(e => recordedError = e);
|
||||
fixture.componentInstance.cond = true;
|
||||
advance(fixture);
|
||||
|
||||
expect(recordedError.message).toEqual('Cannot find primary outlet to load \'BlankCmp\'');
|
||||
expect(fixture.nativeElement).toHaveText('[simple]');
|
||||
}));
|
||||
|
||||
it('should update location when navigating', fakeAsync(() => {
|
||||
@@ -3230,15 +3236,17 @@ describe('Integration', () => {
|
||||
shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; }
|
||||
store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {}
|
||||
shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; }
|
||||
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle { return null !; }
|
||||
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null { return null; }
|
||||
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
|
||||
if (future.routeConfig !== curr.routeConfig) {
|
||||
return false;
|
||||
} else if (Object.keys(future.params).length !== Object.keys(curr.params).length) {
|
||||
return false;
|
||||
} else {
|
||||
return Object.keys(future.params).every(k => future.params[k] === curr.params[k]);
|
||||
}
|
||||
|
||||
if (Object.keys(future.params).length !== Object.keys(curr.params).length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Object.keys(future.params).every(k => future.params[k] === curr.params[k]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3249,8 +3257,12 @@ describe('Integration', () => {
|
||||
router.routeReuseStrategy = new AttachDetachReuseStrategy();
|
||||
|
||||
router.resetConfig([
|
||||
{path: 'a', component: TeamCmp, children: [{path: 'b', component: SimpleCmp}]},
|
||||
{path: 'c', component: UserCmp}
|
||||
{
|
||||
path: 'a',
|
||||
component: TeamCmp,
|
||||
children: [{path: 'b', component: SimpleCmp}],
|
||||
},
|
||||
{path: 'c', component: UserCmp},
|
||||
]);
|
||||
|
||||
router.navigateByUrl('/a/b');
|
||||
@@ -3459,7 +3471,7 @@ class RelativeLinkInIfCmp {
|
||||
|
||||
@Component(
|
||||
{selector: 'child', template: '<div *ngIf="alwaysTrue"><router-outlet></router-outlet></div>'})
|
||||
class LinkInNgIf {
|
||||
class OutletInNgIf {
|
||||
alwaysTrue = true;
|
||||
}
|
||||
|
||||
@@ -3538,7 +3550,7 @@ function createRoot(router: Router, type: any): ComponentFixture<any> {
|
||||
QueryParamsAndFragmentCmp,
|
||||
StringLinkButtonCmp,
|
||||
WrapperCmp,
|
||||
LinkInNgIf,
|
||||
OutletInNgIf,
|
||||
ComponentRecordingRoutePathAndUrl,
|
||||
RouteCmp,
|
||||
RootCmp,
|
||||
@@ -3564,7 +3576,7 @@ function createRoot(router: Router, type: any): ComponentFixture<any> {
|
||||
QueryParamsAndFragmentCmp,
|
||||
StringLinkButtonCmp,
|
||||
WrapperCmp,
|
||||
LinkInNgIf,
|
||||
OutletInNgIf,
|
||||
ComponentRecordingRoutePathAndUrl,
|
||||
RouteCmp,
|
||||
RootCmp,
|
||||
@@ -3592,7 +3604,7 @@ function createRoot(router: Router, type: any): ComponentFixture<any> {
|
||||
QueryParamsAndFragmentCmp,
|
||||
StringLinkButtonCmp,
|
||||
WrapperCmp,
|
||||
LinkInNgIf,
|
||||
OutletInNgIf,
|
||||
ComponentRecordingRoutePathAndUrl,
|
||||
RouteCmp,
|
||||
RootCmp,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {TestBed, inject} from '@angular/core/testing';
|
||||
|
||||
import {ResolveData} from '../src/config';
|
||||
import {PreActivation, Router} from '../src/router';
|
||||
import {RouterOutletMap} from '../src/router_outlet_map';
|
||||
import {ChildrenOutletContexts} from '../src/router_outlet_context';
|
||||
import {ActivatedRouteSnapshot, RouterStateSnapshot, createEmptyStateSnapshot} from '../src/router_state';
|
||||
import {DefaultUrlSerializer} from '../src/url_tree';
|
||||
import {TreeNode} from '../src/utils/tree';
|
||||
@@ -109,7 +109,7 @@ describe('Router', () => {
|
||||
function checkResolveData(
|
||||
future: RouterStateSnapshot, curr: RouterStateSnapshot, injector: any, check: any): void {
|
||||
const p = new PreActivation(future, curr, injector);
|
||||
p.traverse(new RouterOutletMap());
|
||||
p.traverse(new ChildrenOutletContexts());
|
||||
p.resolveData().subscribe(check, (e) => { throw e; });
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import {Location, LocationStrategy} from '@angular/common';
|
||||
import {MockLocationStrategy, SpyLocation} from '@angular/common/testing';
|
||||
import {Compiler, Injectable, Injector, ModuleWithProviders, NgModule, NgModuleFactory, NgModuleFactoryLoader, Optional} from '@angular/core';
|
||||
import {NoPreloading, PreloadingStrategy, ROUTES, Route, Router, RouterModule, RouterOutletMap, Routes, UrlHandlingStrategy, UrlSerializer, provideRoutes, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵflatten as flatten} from '@angular/router';
|
||||
import {ChildrenOutletContexts, NoPreloading, PreloadingStrategy, ROUTES, Route, Router, RouterModule, Routes, UrlHandlingStrategy, UrlSerializer, provideRoutes, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵflatten as flatten} from '@angular/router';
|
||||
|
||||
|
||||
|
||||
@@ -82,11 +82,11 @@ export class SpyNgModuleFactoryLoader implements NgModuleFactoryLoader {
|
||||
* @stable
|
||||
*/
|
||||
export function setupTestingRouter(
|
||||
urlSerializer: UrlSerializer, outletMap: RouterOutletMap, location: Location,
|
||||
urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location,
|
||||
loader: NgModuleFactoryLoader, compiler: Compiler, injector: Injector, routes: Route[][],
|
||||
urlHandlingStrategy?: UrlHandlingStrategy) {
|
||||
const router = new Router(
|
||||
null !, urlSerializer, outletMap, location, injector, loader, compiler, flatten(routes));
|
||||
null !, urlSerializer, contexts, location, injector, loader, compiler, flatten(routes));
|
||||
if (urlHandlingStrategy) {
|
||||
router.urlHandlingStrategy = urlHandlingStrategy;
|
||||
}
|
||||
@@ -127,8 +127,8 @@ export function setupTestingRouter(
|
||||
provide: Router,
|
||||
useFactory: setupTestingRouter,
|
||||
deps: [
|
||||
UrlSerializer, RouterOutletMap, Location, NgModuleFactoryLoader, Compiler, Injector, ROUTES,
|
||||
[UrlHandlingStrategy, new Optional()]
|
||||
UrlSerializer, ChildrenOutletContexts, Location, NgModuleFactoryLoader, Compiler, Injector,
|
||||
ROUTES, [UrlHandlingStrategy, new Optional()]
|
||||
]
|
||||
},
|
||||
{provide: PreloadingStrategy, useExisting: NoPreloading}, provideRoutes([])
|
||||
|
||||
+24
-12
@@ -59,6 +59,16 @@ export interface CanLoad {
|
||||
canLoad(route: Route): Observable<boolean> | Promise<boolean> | boolean;
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
export declare class ChildrenOutletContexts {
|
||||
getContext(childName: string): OutletContext | null;
|
||||
getOrCreateContext(childName: string): OutletContext;
|
||||
onChildOutletCreated(childName: string, outlet: RouterOutlet): void;
|
||||
onChildOutletDestroyed(childName: string): void;
|
||||
onOutletDeactivated(): Map<string, OutletContext>;
|
||||
onOutletReAttached(contexts: Map<string, OutletContext>): void;
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
export declare function convertToParamMap(params: Params): ParamMap;
|
||||
|
||||
@@ -157,6 +167,15 @@ export declare class NoPreloading implements PreloadingStrategy {
|
||||
preload(route: Route, fn: () => Observable<any>): Observable<any>;
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
export declare class OutletContext {
|
||||
attachRef: ComponentRef<any> | null;
|
||||
children: ChildrenOutletContexts;
|
||||
outlet: RouterOutlet | null;
|
||||
resolver: ComponentFactoryResolver | null;
|
||||
route: ActivatedRoute | null;
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
export interface ParamMap {
|
||||
readonly keys: string[];
|
||||
@@ -239,7 +258,7 @@ export declare class Router {
|
||||
readonly routerState: RouterState;
|
||||
readonly url: string;
|
||||
urlHandlingStrategy: UrlHandlingStrategy;
|
||||
constructor(rootComponentType: Type<any> | null, urlSerializer: UrlSerializer, outletMap: RouterOutletMap, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes);
|
||||
constructor(rootComponentType: Type<any> | null, urlSerializer: UrlSerializer, rootContexts: ChildrenOutletContexts, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes);
|
||||
createUrlTree(commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, queryParamsHandling, preserveFragment}?: NavigationExtras): UrlTree;
|
||||
dispose(): void;
|
||||
initialNavigation(): void;
|
||||
@@ -329,7 +348,7 @@ export declare class RouterModule {
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
export declare class RouterOutlet implements OnDestroy {
|
||||
export declare class RouterOutlet implements OnDestroy, OnInit {
|
||||
activateEvents: EventEmitter<any>;
|
||||
readonly activatedRoute: ActivatedRoute;
|
||||
readonly component: Object;
|
||||
@@ -337,20 +356,13 @@ export declare class RouterOutlet implements OnDestroy {
|
||||
readonly isActivated: boolean;
|
||||
/** @deprecated */ readonly locationFactoryResolver: ComponentFactoryResolver;
|
||||
/** @deprecated */ readonly locationInjector: Injector;
|
||||
outletMap: RouterOutletMap;
|
||||
constructor(parentOutletMap: RouterOutletMap, location: ViewContainerRef, resolver: ComponentFactoryResolver, name: string);
|
||||
/** @deprecated */ activate(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver, injector: Injector, providers: ResolvedReflectiveProvider[], outletMap: RouterOutletMap): void;
|
||||
activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null, outletMap: RouterOutletMap): void;
|
||||
constructor(parentContexts: ChildrenOutletContexts, location: ViewContainerRef, resolver: ComponentFactoryResolver, name: string);
|
||||
activateWith(activatedRoute: ActivatedRoute, resolver: ComponentFactoryResolver | null): void;
|
||||
attach(ref: ComponentRef<any>, activatedRoute: ActivatedRoute): void;
|
||||
deactivate(): void;
|
||||
detach(): ComponentRef<any>;
|
||||
ngOnDestroy(): void;
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
export declare class RouterOutletMap {
|
||||
registerOutlet(name: string, outlet: RouterOutlet): void;
|
||||
removeOutlet(name: string): void;
|
||||
ngOnInit(): void;
|
||||
}
|
||||
|
||||
/** @stable */
|
||||
|
||||
Reference in New Issue
Block a user