Starting with Angular 2.3 (and the corresponding Router 3.3), developers can leverage sticky routes. This feature allows a component's state to persist when its route is deactivated, making it available again when the route is revisited. To achieve this, the application can supply a custom strategy for component reuse. In this post, we'll walk through a working example available on GitHub.
This guide covers the fundamentals, and it’s likely that Victor Savkin, the router's core maintainer, will follow up with a more detailed explanation in the coming days.
To demonstrate sticky routes in action, let's consider a sample app with a route that lets users search for flights. They can then pick one from the returned results:
Given that this route's component stores its internal state in its own properties, that state vanishes the moment the user navigates away to a different route. Upon returning to the search route, the user is greeted by an empty result set:
Sticky routes change this behavior by reusing the previous component state, so the user is presented with the last search results once they navigate back.
To enable sticky routes, your application must implement or extend the abstract class RouteReuseStrategy:
// Taken from angular's source code at github:
export declare 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.
*/
abstract store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void;
/**
* Determines if this route (and its subtree) should be reattached.
*/
abstract shouldAttach(route: ActivatedRouteSnapshot): boolean;
/**
* Retrieves the previously stored route.
*/
abstract retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle;
/**
* Determines if a route should be reused.
*/
abstract shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean;
}
As indicated in the above snippet's comments, the RouteReuseStrategy is responsible for determining two things: whether the router should cache the active route upon deactivation, and whether it should restore a cached route upon re-activation. Furthermore, it also manages the actual storage and retrieval of those routes.
Below is a straightforward implementation of such a strategy, storing routes in a map called handlers:
// This impl. bases upon one that can be found in the router's test cases.
export class CustomReuseStrategy implements RouteReuseStrategy {
handlers: {[key: string]: DetachedRouteHandle} = {};
shouldDetach(route: ActivatedRouteSnapshot): boolean {
console.debug('CustomReuseStrategy:shouldDetach', route);
return true;
}
store(route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void {
console.debug('CustomReuseStrategy:store', route, handle);
this.handlers[route.routeConfig.path] = handle;
}
shouldAttach(route: ActivatedRouteSnapshot): boolean {
console.debug('CustomReuseStrategy:shouldAttach', route);
return !!route.routeConfig && !!this.handlers[route.routeConfig.path];
}
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle {
console.debug('CustomReuseStrategy:retrieve', route);
if (!route.routeConfig) return null;
return this.handlers[route.routeConfig.path];
}
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
console.debug('CustomReuseStrategy:shouldReuseRoute', future, curr);
return future.routeConfig === curr.routeConfig;
}
}
To put your custom RouteReuseStrategy into effect, you need to provide it within your application's configuration:
@NgModule({
[...],
providers: [
{provide: RouteReuseStrategy, useClass: CustomReuseStrategy}
]
)}
export class AppModule {
}
Once that’s in place, your app should exhibit the desired behavior described earlier. As pointed out, the full implementation is available in my GitHub repository.


