Router Fixes (#10579)
* fix(router): copy over data during data resolution * fix(router): components instantiated in lazy-loaded modules should use location's injector
This commit is contained in:
parent
9a11ec2624
commit
6db27153ef
|
@ -104,7 +104,6 @@ export class RouterOutlet implements OnDestroy {
|
||||||
}
|
}
|
||||||
|
|
||||||
const injector = loadedInjector ? loadedInjector : this.location.parentInjector;
|
const injector = loadedInjector ? loadedInjector : this.location.parentInjector;
|
||||||
|
|
||||||
const inj = ReflectiveInjector.fromResolvedProviders(providers, injector);
|
const inj = ReflectiveInjector.fromResolvedProviders(providers, injector);
|
||||||
this.activated = this.location.createComponent(factory, this.location.length, inj, []);
|
this.activated = this.location.createComponent(factory, this.location.length, inj, []);
|
||||||
this.activated.changeDetectorRef.detectChanges();
|
this.activated.changeDetectorRef.detectChanges();
|
||||||
|
|
|
@ -447,7 +447,6 @@ export class Router {
|
||||||
|
|
||||||
class CanActivate {
|
class CanActivate {
|
||||||
constructor(public path: ActivatedRouteSnapshot[]) {}
|
constructor(public path: ActivatedRouteSnapshot[]) {}
|
||||||
|
|
||||||
get route(): ActivatedRouteSnapshot { return this.path[this.path.length - 1]; }
|
get route(): ActivatedRouteSnapshot { return this.path[this.path.length - 1]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,7 +455,7 @@ class CanDeactivate {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class PreActivation {
|
export class PreActivation {
|
||||||
private checks: Array<CanActivate|CanDeactivate> = [];
|
private checks: Array<CanActivate|CanDeactivate> = [];
|
||||||
constructor(
|
constructor(
|
||||||
private future: RouterStateSnapshot, private curr: RouterStateSnapshot,
|
private future: RouterStateSnapshot, private curr: RouterStateSnapshot,
|
||||||
|
@ -504,6 +503,7 @@ class PreActivation {
|
||||||
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>,
|
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>,
|
||||||
outletMap: RouterOutletMap, futurePath: ActivatedRouteSnapshot[]): void {
|
outletMap: RouterOutletMap, futurePath: ActivatedRouteSnapshot[]): void {
|
||||||
const prevChildren: {[key: string]: any} = nodeChildrenAsMap(currNode);
|
const prevChildren: {[key: string]: any} = nodeChildrenAsMap(currNode);
|
||||||
|
|
||||||
futureNode.children.forEach(c => {
|
futureNode.children.forEach(c => {
|
||||||
this.traverseRoutes(c, prevChildren[c.value.outlet], outletMap, futurePath.concat([c.value]));
|
this.traverseRoutes(c, prevChildren[c.value.outlet], outletMap, futurePath.concat([c.value]));
|
||||||
delete prevChildren[c.value.outlet];
|
delete prevChildren[c.value.outlet];
|
||||||
|
@ -524,6 +524,9 @@ class PreActivation {
|
||||||
if (curr && future._routeConfig === curr._routeConfig) {
|
if (curr && future._routeConfig === curr._routeConfig) {
|
||||||
if (!shallowEqual(future.params, curr.params)) {
|
if (!shallowEqual(future.params, curr.params)) {
|
||||||
this.checks.push(new CanDeactivate(outlet.component, curr), new CanActivate(futurePath));
|
this.checks.push(new CanDeactivate(outlet.component, curr), new CanActivate(futurePath));
|
||||||
|
} else {
|
||||||
|
// we need to set the data
|
||||||
|
future.data = curr.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a component, we need to go through an outlet.
|
// If we have a component, we need to go through an outlet.
|
||||||
|
@ -578,7 +581,7 @@ class PreActivation {
|
||||||
const canActivate = future._routeConfig ? future._routeConfig.canActivate : null;
|
const canActivate = future._routeConfig ? future._routeConfig.canActivate : null;
|
||||||
if (!canActivate || canActivate.length === 0) return of (true);
|
if (!canActivate || canActivate.length === 0) return of (true);
|
||||||
const obs = from(canActivate).map(c => {
|
const obs = from(canActivate).map(c => {
|
||||||
const guard = this.getToken(c, future, this.future);
|
const guard = this.getToken(c, future);
|
||||||
if (guard.canActivate) {
|
if (guard.canActivate) {
|
||||||
return wrapIntoObservable(guard.canActivate(future, this.future));
|
return wrapIntoObservable(guard.canActivate(future, this.future));
|
||||||
} else {
|
} else {
|
||||||
|
@ -598,7 +601,7 @@ class PreActivation {
|
||||||
|
|
||||||
return andObservables(from(canActivateChildGuards).map(d => {
|
return andObservables(from(canActivateChildGuards).map(d => {
|
||||||
const obs = from(d.guards).map(c => {
|
const obs = from(d.guards).map(c => {
|
||||||
const guard = this.getToken(c, c.node, this.future);
|
const guard = this.getToken(c, c.node);
|
||||||
if (guard.canActivateChild) {
|
if (guard.canActivateChild) {
|
||||||
return wrapIntoObservable(guard.canActivateChild(future, this.future));
|
return wrapIntoObservable(guard.canActivateChild(future, this.future));
|
||||||
} else {
|
} else {
|
||||||
|
@ -621,7 +624,7 @@ class PreActivation {
|
||||||
if (!canDeactivate || canDeactivate.length === 0) return of (true);
|
if (!canDeactivate || canDeactivate.length === 0) return of (true);
|
||||||
return from(canDeactivate)
|
return from(canDeactivate)
|
||||||
.map(c => {
|
.map(c => {
|
||||||
const guard = this.getToken(c, curr, this.curr);
|
const guard = this.getToken(c, curr);
|
||||||
if (guard.canDeactivate) {
|
if (guard.canDeactivate) {
|
||||||
return wrapIntoObservable(guard.canDeactivate(component, curr, this.curr));
|
return wrapIntoObservable(guard.canDeactivate(component, curr, this.curr));
|
||||||
} else {
|
} else {
|
||||||
|
@ -643,14 +646,14 @@ class PreActivation {
|
||||||
|
|
||||||
private resolveNode(resolve: ResolveData, future: ActivatedRouteSnapshot): Observable<any> {
|
private resolveNode(resolve: ResolveData, future: ActivatedRouteSnapshot): Observable<any> {
|
||||||
return waitForMap(resolve, (k, v) => {
|
return waitForMap(resolve, (k, v) => {
|
||||||
const resolver = this.getToken(v, future, this.future);
|
const resolver = this.getToken(v, future);
|
||||||
return resolver.resolve ? wrapIntoObservable(resolver.resolve(future, this.future)) :
|
return resolver.resolve ? wrapIntoObservable(resolver.resolve(future, this.future)) :
|
||||||
wrapIntoObservable(resolver(future, this.future));
|
wrapIntoObservable(resolver(future, this.future));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private getToken(token: any, snapshot: ActivatedRouteSnapshot, state: RouterStateSnapshot): any {
|
private getToken(token: any, snapshot: ActivatedRouteSnapshot): any {
|
||||||
const config = closestLoadedConfig(state, snapshot);
|
const config = closestLoadedConfig(snapshot);
|
||||||
const injector = config ? config.injector : this.injector;
|
const injector = config ? config.injector : this.injector;
|
||||||
return injector.get(token);
|
return injector.get(token);
|
||||||
}
|
}
|
||||||
|
@ -736,7 +739,8 @@ class ActivateRoutes {
|
||||||
useValue: outletMap
|
useValue: outletMap
|
||||||
}];
|
}];
|
||||||
|
|
||||||
const config = closestLoadedConfig(this.futureState.snapshot, future.snapshot);
|
const config = parentLoadedConfig(future.snapshot);
|
||||||
|
|
||||||
let loadedFactoryResolver: ComponentFactoryResolver = null;
|
let loadedFactoryResolver: ComponentFactoryResolver = null;
|
||||||
let loadedInjector: Injector = null;
|
let loadedInjector: Injector = null;
|
||||||
|
|
||||||
|
@ -744,8 +748,7 @@ class ActivateRoutes {
|
||||||
loadedFactoryResolver = config.factoryResolver;
|
loadedFactoryResolver = config.factoryResolver;
|
||||||
loadedInjector = config.injector;
|
loadedInjector = config.injector;
|
||||||
resolved.push({provide: ComponentFactoryResolver, useValue: loadedFactoryResolver});
|
resolved.push({provide: ComponentFactoryResolver, useValue: loadedFactoryResolver});
|
||||||
};
|
}
|
||||||
|
|
||||||
outlet.activate(
|
outlet.activate(
|
||||||
future, loadedFactoryResolver, loadedInjector, ReflectiveInjector.resolve(resolved),
|
future, loadedFactoryResolver, loadedInjector, ReflectiveInjector.resolve(resolved),
|
||||||
outletMap);
|
outletMap);
|
||||||
|
@ -763,13 +766,27 @@ class ActivateRoutes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function closestLoadedConfig(
|
function parentLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConfig {
|
||||||
state: RouterStateSnapshot, snapshot: ActivatedRouteSnapshot): LoadedRouterConfig {
|
let s = snapshot.parent;
|
||||||
const b = state.pathFromRoot(snapshot).filter(s => {
|
while (s) {
|
||||||
const config = (<any>s)._routeConfig;
|
const c: any = s._routeConfig;
|
||||||
return config && config._loadedConfig && s !== snapshot;
|
if (c && c._loadedConfig) return c._loadedConfig;
|
||||||
});
|
if (c && c.component) return null;
|
||||||
return b.length > 0 ? (<any>b[b.length - 1])._routeConfig._loadedConfig : null;
|
s = s.parent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function closestLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConfig {
|
||||||
|
if (!snapshot) return null;
|
||||||
|
|
||||||
|
let s = snapshot.parent;
|
||||||
|
while (s) {
|
||||||
|
const c: any = s._routeConfig;
|
||||||
|
if (c && c._loadedConfig) return c._loadedConfig;
|
||||||
|
s = s.parent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function nodeChildrenAsMap(node: TreeNode<any>) {
|
function nodeChildrenAsMap(node: TreeNode<any>) {
|
||||||
|
|
|
@ -70,7 +70,8 @@ export function createEmptyState(urlTree: UrlTree, rootComponent: Type): RouterS
|
||||||
return new RouterState(new TreeNode<ActivatedRoute>(activated, []), snapshot);
|
return new RouterState(new TreeNode<ActivatedRoute>(activated, []), snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createEmptyStateSnapshot(urlTree: UrlTree, rootComponent: Type): RouterStateSnapshot {
|
export function createEmptyStateSnapshot(
|
||||||
|
urlTree: UrlTree, rootComponent: Type): RouterStateSnapshot {
|
||||||
const emptyParams = {};
|
const emptyParams = {};
|
||||||
const emptyData = {};
|
const emptyData = {};
|
||||||
const emptyQueryParams = {};
|
const emptyQueryParams = {};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -34,6 +34,7 @@
|
||||||
"test/config.spec.ts",
|
"test/config.spec.ts",
|
||||||
"test/router_state.spec.ts",
|
"test/router_state.spec.ts",
|
||||||
"test/router.spec.ts",
|
"test/router.spec.ts",
|
||||||
|
"test/integration.spec.ts",
|
||||||
"../../../node_modules/@types/jasmine/index.d.ts"
|
"../../../node_modules/@types/jasmine/index.d.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue