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 inj = ReflectiveInjector.fromResolvedProviders(providers, injector);
|
||||
this.activated = this.location.createComponent(factory, this.location.length, inj, []);
|
||||
this.activated.changeDetectorRef.detectChanges();
|
||||
|
|
|
@ -447,7 +447,6 @@ export class Router {
|
|||
|
||||
class CanActivate {
|
||||
constructor(public path: ActivatedRouteSnapshot[]) {}
|
||||
|
||||
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> = [];
|
||||
constructor(
|
||||
private future: RouterStateSnapshot, private curr: RouterStateSnapshot,
|
||||
|
@ -504,6 +503,7 @@ class PreActivation {
|
|||
futureNode: TreeNode<ActivatedRouteSnapshot>, currNode: TreeNode<ActivatedRouteSnapshot>,
|
||||
outletMap: RouterOutletMap, futurePath: ActivatedRouteSnapshot[]): void {
|
||||
const prevChildren: {[key: string]: any} = nodeChildrenAsMap(currNode);
|
||||
|
||||
futureNode.children.forEach(c => {
|
||||
this.traverseRoutes(c, prevChildren[c.value.outlet], outletMap, futurePath.concat([c.value]));
|
||||
delete prevChildren[c.value.outlet];
|
||||
|
@ -524,6 +524,9 @@ class PreActivation {
|
|||
if (curr && future._routeConfig === curr._routeConfig) {
|
||||
if (!shallowEqual(future.params, curr.params)) {
|
||||
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.
|
||||
|
@ -578,7 +581,7 @@ class PreActivation {
|
|||
const canActivate = future._routeConfig ? future._routeConfig.canActivate : null;
|
||||
if (!canActivate || canActivate.length === 0) return of (true);
|
||||
const obs = from(canActivate).map(c => {
|
||||
const guard = this.getToken(c, future, this.future);
|
||||
const guard = this.getToken(c, future);
|
||||
if (guard.canActivate) {
|
||||
return wrapIntoObservable(guard.canActivate(future, this.future));
|
||||
} else {
|
||||
|
@ -598,7 +601,7 @@ class PreActivation {
|
|||
|
||||
return andObservables(from(canActivateChildGuards).map(d => {
|
||||
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) {
|
||||
return wrapIntoObservable(guard.canActivateChild(future, this.future));
|
||||
} else {
|
||||
|
@ -621,7 +624,7 @@ class PreActivation {
|
|||
if (!canDeactivate || canDeactivate.length === 0) return of (true);
|
||||
return from(canDeactivate)
|
||||
.map(c => {
|
||||
const guard = this.getToken(c, curr, this.curr);
|
||||
const guard = this.getToken(c, curr);
|
||||
if (guard.canDeactivate) {
|
||||
return wrapIntoObservable(guard.canDeactivate(component, curr, this.curr));
|
||||
} else {
|
||||
|
@ -643,14 +646,14 @@ class PreActivation {
|
|||
|
||||
private resolveNode(resolve: ResolveData, future: ActivatedRouteSnapshot): Observable<any> {
|
||||
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)) :
|
||||
wrapIntoObservable(resolver(future, this.future));
|
||||
});
|
||||
}
|
||||
|
||||
private getToken(token: any, snapshot: ActivatedRouteSnapshot, state: RouterStateSnapshot): any {
|
||||
const config = closestLoadedConfig(state, snapshot);
|
||||
private getToken(token: any, snapshot: ActivatedRouteSnapshot): any {
|
||||
const config = closestLoadedConfig(snapshot);
|
||||
const injector = config ? config.injector : this.injector;
|
||||
return injector.get(token);
|
||||
}
|
||||
|
@ -736,7 +739,8 @@ class ActivateRoutes {
|
|||
useValue: outletMap
|
||||
}];
|
||||
|
||||
const config = closestLoadedConfig(this.futureState.snapshot, future.snapshot);
|
||||
const config = parentLoadedConfig(future.snapshot);
|
||||
|
||||
let loadedFactoryResolver: ComponentFactoryResolver = null;
|
||||
let loadedInjector: Injector = null;
|
||||
|
||||
|
@ -744,8 +748,7 @@ class ActivateRoutes {
|
|||
loadedFactoryResolver = config.factoryResolver;
|
||||
loadedInjector = config.injector;
|
||||
resolved.push({provide: ComponentFactoryResolver, useValue: loadedFactoryResolver});
|
||||
};
|
||||
|
||||
}
|
||||
outlet.activate(
|
||||
future, loadedFactoryResolver, loadedInjector, ReflectiveInjector.resolve(resolved),
|
||||
outletMap);
|
||||
|
@ -763,13 +766,27 @@ class ActivateRoutes {
|
|||
}
|
||||
}
|
||||
|
||||
function closestLoadedConfig(
|
||||
state: RouterStateSnapshot, snapshot: ActivatedRouteSnapshot): LoadedRouterConfig {
|
||||
const b = state.pathFromRoot(snapshot).filter(s => {
|
||||
const config = (<any>s)._routeConfig;
|
||||
return config && config._loadedConfig && s !== snapshot;
|
||||
});
|
||||
return b.length > 0 ? (<any>b[b.length - 1])._routeConfig._loadedConfig : null;
|
||||
function parentLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConfig {
|
||||
let s = snapshot.parent;
|
||||
while (s) {
|
||||
const c: any = s._routeConfig;
|
||||
if (c && c._loadedConfig) return c._loadedConfig;
|
||||
if (c && c.component) return 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>) {
|
||||
|
|
|
@ -70,7 +70,8 @@ export function createEmptyState(urlTree: UrlTree, rootComponent: Type): RouterS
|
|||
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 emptyData = {};
|
||||
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/router_state.spec.ts",
|
||||
"test/router.spec.ts",
|
||||
"test/integration.spec.ts",
|
||||
"../../../node_modules/@types/jasmine/index.d.ts"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue