Skip to content
Permalink
Browse files

feat(router): add events tracking activation of individual routes

* Adds `ChildActivationStart` and `ChildActivationEnd`
* Adds test to verify the PreActivation phase of routing
  • Loading branch information...
jasonaden authored and alxhub committed Jul 25, 2017
1 parent 82b067f commit 49cd8513e457b6c795dbbdf7a0573fe98e2c19a9
@@ -10,17 +10,66 @@ import {Route} from './config';
import {RouterStateSnapshot} from './router_state';

/**
* @whatItDoes Represents an event triggered when a navigation starts.
* @whatItDoes Base for events the Router goes through, as opposed to events tied to a specific
* Route. `RouterEvent`s will only be fired one time for any given navigation.
*
* @stable
* Example:
*
* ```
* class MyService {
* constructor(public router: Router, logger: Logger) {
* router.events.filter(e => e instanceof RouterEvent).subscribe(e => {
* logger.log(e.id, e.url);
* });
* }
* }
* ```
*
* @experimental
*/
export class NavigationStart {
export class RouterEvent {
constructor(
/** @docsNotRequired */
public id: number,
/** @docsNotRequired */
public url: string) {}
}

/**
* @whatItDoes Base for events tied to a specific `Route`, as opposed to events for the Router
* lifecycle. `RouteEvent`s may be fired multiple times during a single navigation and will
* always receive the `Route` they pertain to.
*
* Example:
*
* ```
* class MyService {
* constructor(public router: Router, spinner: Spinner) {
* router.events.filter(e => e instanceof RouteEvent).subscribe(e => {
* if (e instanceof ChildActivationStart) {
* spinner.start(e.route);
* } else if (e instanceof ChildActivationEnd) {
* spinner.end(e.route);
* }
* });
* }
* }
* ```
*
* @experimental
*/
export class RouteEvent {
constructor(
/** @docsNotRequired */
public route: Route) {}
}

/**
* @whatItDoes Represents an event triggered when a navigation starts.
*
* @stable
*/
export class NavigationStart extends RouterEvent {
/** @docsNotRequired */
toString(): string { return `NavigationStart(id: ${this.id}, url: '${this.url}')`; }
}
@@ -30,14 +79,16 @@ export class NavigationStart {
*
* @stable
*/
export class NavigationEnd {
export class NavigationEnd extends RouterEvent {
constructor(
/** @docsNotRequired */
public id: number,
id: number,
/** @docsNotRequired */
public url: string,
url: string,
/** @docsNotRequired */
public urlAfterRedirects: string) {}
public urlAfterRedirects: string) {
super(id, url);
}

/** @docsNotRequired */
toString(): string {
@@ -50,14 +101,16 @@ export class NavigationEnd {
*
* @stable
*/
export class NavigationCancel {
export class NavigationCancel extends RouterEvent {
constructor(
/** @docsNotRequired */
public id: number,
id: number,
/** @docsNotRequired */
public url: string,
url: string,
/** @docsNotRequired */
public reason: string) {}
public reason: string) {
super(id, url);
}

/** @docsNotRequired */
toString(): string { return `NavigationCancel(id: ${this.id}, url: '${this.url}')`; }
@@ -68,14 +121,16 @@ export class NavigationCancel {
*
* @stable
*/
export class NavigationError {
export class NavigationError extends RouterEvent {
constructor(
/** @docsNotRequired */
public id: number,
id: number,
/** @docsNotRequired */
public url: string,
url: string,
/** @docsNotRequired */
public error: any) {}
public error: any) {
super(id, url);
}

/** @docsNotRequired */
toString(): string {
@@ -88,60 +143,42 @@ export class NavigationError {
*
* @stable
*/
export class RoutesRecognized {
export class RoutesRecognized extends RouterEvent {
constructor(
/** @docsNotRequired */
public id: number,
id: number,
/** @docsNotRequired */
public url: string,
url: string,
/** @docsNotRequired */
public urlAfterRedirects: string,
/** @docsNotRequired */
public state: RouterStateSnapshot) {}
public state: RouterStateSnapshot) {
super(id, url);
}

/** @docsNotRequired */
toString(): string {
return `RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
}
}

/**
* @whatItDoes Represents an event triggered before lazy loading a route config.
*
* @experimental
*/
export class RouteConfigLoadStart {
constructor(public route: Route) {}

toString(): string { return `RouteConfigLoadStart(path: ${this.route.path})`; }
}

/**
* @whatItDoes Represents an event triggered when a route has been lazy loaded.
*
* @experimental
*/
export class RouteConfigLoadEnd {
constructor(public route: Route) {}

toString(): string { return `RouteConfigLoadEnd(path: ${this.route.path})`; }
}

/**
* @whatItDoes Represents the start of the Guard phase of routing.
*
* @experimental
*/
export class GuardsCheckStart {
export class GuardsCheckStart extends RouterEvent {
constructor(
/** @docsNotRequired */
public id: number,
id: number,
/** @docsNotRequired */
public url: string,
url: string,
/** @docsNotRequired */
public urlAfterRedirects: string,
/** @docsNotRequired */
public state: RouterStateSnapshot) {}
public state: RouterStateSnapshot) {
super(id, url);
}

toString(): string {
return `GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
@@ -153,18 +190,20 @@ export class GuardsCheckStart {
*
* @experimental
*/
export class GuardsCheckEnd {
export class GuardsCheckEnd extends RouterEvent {
constructor(
/** @docsNotRequired */
public id: number,
id: number,
/** @docsNotRequired */
public url: string,
url: string,
/** @docsNotRequired */
public urlAfterRedirects: string,
/** @docsNotRequired */
public state: RouterStateSnapshot,
/** @docsNotRequired */
public shouldActivate: boolean) {}
public shouldActivate: boolean) {
super(id, url);
}

toString(): string {
return `GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`;
@@ -179,16 +218,18 @@ export class GuardsCheckEnd {
*
* @experimental
*/
export class ResolveStart {
export class ResolveStart extends RouterEvent {
constructor(
/** @docsNotRequired */
public id: number,
id: number,
/** @docsNotRequired */
public url: string,
url: string,
/** @docsNotRequired */
public urlAfterRedirects: string,
/** @docsNotRequired */
public state: RouterStateSnapshot) {}
public state: RouterStateSnapshot) {
super(id, url);
}

toString(): string {
return `ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
@@ -201,22 +242,62 @@ export class ResolveStart {
*
* @experimental
*/
export class ResolveEnd {
export class ResolveEnd extends RouterEvent {
constructor(
/** @docsNotRequired */
public id: number,
id: number,
/** @docsNotRequired */
public url: string,
url: string,
/** @docsNotRequired */
public urlAfterRedirects: string,
/** @docsNotRequired */
public state: RouterStateSnapshot) {}
public state: RouterStateSnapshot) {
super(id, url);
}

toString(): string {
return `ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`;
}
}

/**
* @whatItDoes Represents an event triggered before lazy loading a route config.
*
* @experimental
*/
export class RouteConfigLoadStart extends RouteEvent {
toString(): string { return `RouteConfigLoadStart(path: ${this.route.path})`; }
}

/**
* @whatItDoes Represents an event triggered when a route has been lazy loaded.
*
* @experimental
*/
export class RouteConfigLoadEnd extends RouteEvent {
toString(): string { return `RouteConfigLoadEnd(path: ${this.route.path})`; }
}

/**
* @whatItDoes Represents the start of end of the Resolve phase of routing. See note on
* {@link ChildActivationEnd} for use of this experimental API.
*
* @experimental
*/
export class ChildActivationStart extends RouteEvent {
toString(): string { return `ChildActivationStart(path: '${this.route.path}')`; }
}

/**
* @whatItDoes Represents the start of end of the Resolve phase of routing. See note on
* {@link ChildActivationStart} for use of this experimental API.
*
* @experimental
*/
export class ChildActivationEnd extends RouteEvent {
toString(): string { return `ChildActivationEnd(path: '${this.route.path}')`; }
}

/**
* @whatItDoes Represents a router event, allowing you to track the lifecycle of the router.
*
@@ -227,15 +308,15 @@ export class ResolveEnd {
* - {@link RouteConfigLoadEnd},
* - {@link RoutesRecognized},
* - {@link GuardsCheckStart},
* - {@link ChildActivationStart},
* - {@link GuardsCheckEnd},
* - {@link ResolveStart},
* - {@link ResolveEnd},
* - {@link ChildActivationEnd}
* - {@link NavigationEnd},
* - {@link NavigationCancel},
* - {@link NavigationError}
*
* @stable
*/
export type Event = NavigationStart | NavigationEnd | NavigationCancel | NavigationError |
RoutesRecognized | RouteConfigLoadStart | RouteConfigLoadEnd | GuardsCheckStart |
GuardsCheckEnd | ResolveStart | ResolveEnd;
export type Event = RouterEvent | RouteEvent;
@@ -11,7 +11,7 @@ export {Data, LoadChildren, LoadChildrenCallback, ResolveData, Route, Routes, Ru
export {RouterLink, RouterLinkWithHref} from './directives/router_link';
export {RouterLinkActive} from './directives/router_link_active';
export {RouterOutlet} from './directives/router_outlet';
export {Event, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RoutesRecognized} from './events';
export {ChildActivationEnd, ChildActivationStart, Event, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouteEvent, RoutesRecognized} from './events';
export {CanActivate, CanActivateChild, CanDeactivate, CanLoad, Resolve} from './interfaces';
export {DetachedRouteHandle, RouteReuseStrategy} from './route_reuse_strategy';
export {NavigationExtras, Router} from './router';

2 comments on commit 49cd851

@IgorMinar

This comment has been minimized.

Copy link
Member

replied Aug 1, 2017

@jasonaden can you please check if the router guide doc needs to be updated as well?

@IgorMinar

This comment has been minimized.

Copy link
Member

replied Aug 1, 2017

if it does, can you please send a PR?

Please sign in to comment.
You can’t perform that action at this time.