fix(router): adjust ChildActivation events to only fire when the child is actually changing (#19043)

* The problem was with the `fireChildActivationStart` function. It was taking a `path` param, which was an
array of `ActivatedRouteSnapshot`s. The function was being fired for each piece of the route that was being
activated. This resulted in far too many `ChildActivationStart` events being fired, and being fired on routes
that weren't actually getting activated. This change fires the event only for those routes that are actually
being activated.

fixes #18942

PR Close #19043
This commit is contained in:
Jason Aden
2017-09-04 13:00:59 -07:00
committed by Miško Hevery
parent dce36751f5
commit 66f0ab0371
7 changed files with 186 additions and 39 deletions

View File

@ -7,7 +7,8 @@
*/
import {Route} from './config';
import {RouterStateSnapshot} from './router_state';
import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state';
/**
* @whatItDoes Base for events the Router goes through, as opposed to events tied to a specific
@ -264,8 +265,11 @@ export class RouteConfigLoadEnd {
export class ChildActivationStart {
constructor(
/** @docsNotRequired */
public route: Route) {}
toString(): string { return `ChildActivationStart(path: '${this.route.path}')`; }
public snapshot: ActivatedRouteSnapshot) {}
toString(): string {
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';
return `ChildActivationStart(path: '${path}')`;
}
}
/**
@ -277,8 +281,11 @@ export class ChildActivationStart {
export class ChildActivationEnd {
constructor(
/** @docsNotRequired */
public route: Route) {}
toString(): string { return `ChildActivationEnd(path: '${this.route.path}')`; }
public snapshot: ActivatedRouteSnapshot) {}
toString(): string {
const path = this.snapshot.routeConfig && this.snapshot.routeConfig.path || '';
return `ChildActivationEnd(path: '${path}')`;
}
}
/**

View File

@ -202,8 +202,8 @@ export class PreActivation {
const checks$ = from(this.canActivateChecks);
const runningChecks$ = concatMap.call(
checks$, (check: CanActivate) => andObservables(from([
this.fireChildActivationStart(check.path), this.runCanActivateChild(check.path),
this.runCanActivate(check.route)
this.fireChildActivationStart(check.route.parent),
this.runCanActivateChild(check.path), this.runCanActivate(check.route)
])));
return every.call(runningChecks$, (result: boolean) => result === true);
// this.fireChildActivationStart(check.path),
@ -217,16 +217,11 @@ export class PreActivation {
* return
* `true` so checks continue to run.
*/
private fireChildActivationStart(path: ActivatedRouteSnapshot[]): Observable<boolean> {
if (!this.forwardEvent) return of (true);
const childActivations = path.slice(0, path.length - 1).reverse().filter(_ => _ !== null);
return andObservables(map.call(from(childActivations), (snapshot: ActivatedRouteSnapshot) => {
if (this.forwardEvent && snapshot._routeConfig) {
this.forwardEvent(new ChildActivationStart(snapshot._routeConfig));
}
return of (true);
}));
private fireChildActivationStart(snapshot: ActivatedRouteSnapshot|null): Observable<boolean> {
if (snapshot !== null && this.forwardEvent) {
this.forwardEvent(new ChildActivationStart(snapshot));
}
return of (true);
}
private runCanActivate(future: ActivatedRouteSnapshot): Observable<boolean> {
const canActivate = future._routeConfig ? future._routeConfig.canActivate : null;

View File

@ -21,7 +21,7 @@ import {applyRedirects} from './apply_redirects';
import {LoadedRouterConfig, QueryParamsHandling, Route, Routes, validateConfig} from './config';
import {createRouterState} from './create_router_state';
import {createUrlTree} from './create_url_tree';
import {ChildActivationEnd, Event, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouterEvent, RoutesRecognized} from './events';
import {ChildActivationEnd, Event, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RoutesRecognized} from './events';
import {PreActivation} from './pre_activation';
import {recognize} from './recognize';
import {DefaultRouteReuseStrategy, DetachedRouteHandleInternal, RouteReuseStrategy} from './route_reuse_strategy';
@ -864,8 +864,8 @@ class ActivateRoutes {
const children: {[outlet: string]: any} = nodeChildrenAsMap(currNode);
futureNode.children.forEach(
c => { this.activateRoutes(c, children[c.value.outlet], contexts); });
if (futureNode.children.length && futureNode.value.routeConfig) {
this.forwardEvent(new ChildActivationEnd(futureNode.value.routeConfig));
if (futureNode.children.length) {
this.forwardEvent(new ChildActivationEnd(futureNode.value.snapshot));
}
}