My current configuration:
const routes: Routes = [
{ path: '', component: NavComponent, outlet: 'nav' }, // (1)
{ path: '**', component: NavComponent, outlet: 'nav' } // (2)
];
It works. NavComponent
is always rendered to the outlet nav
. In particular, it works for all the following kinds of URLs:
http://example.com/foo(nav:bar) // (a) non-empty path in nav --> (2)
http://example.com/foo(nav:) // (b) empty path in nav --> (2)
http://example.com/foo // (c) no nav at all --> (1)
Notice that the router matches different routes to these URLs:
(1)
is used for (c)
(2)
is used for (a)
and (b)
That is why the NavComponent
instance is destroyed and recreated every time the location changes say from (c)
to (a)
. And that's something I need to prevent. I need to keep my instance because of its state, animations, etc. As far as I understand, it's possible only if the same route is used for all the URLs, however I can't find a way to do this. If I remove (1)
, the URLs like (c)
stop showing NavComponent
in nav
. Apparently **
doesn't match such URLs (I'm not sure why though).
You can see it in action here: https://stackblitz.com/edit/angular-ptzwrm
What is the proper solution here?
For now, I'm overriding UrlSerializer
to add (nav:)
to URLs like (c)
before parsing, but it feels like a hack.
Dumb question, but can you not simply modify the URL using location service and stay on the same component (and just change states for your animations)?
Otherwise, you can implement a custom RouteReuseStrategy to force reusing your component
import { RouteReuseStrategy } from '@angular/router';
import {ActivatedRouteSnapshot} from '@angular/router';
import { DetachedRouteHandle } from '@angular/router';
/** Use defaults from angular internals, apart from shouldReuseRoute **/
export class CustomReuseStrategy implements RouteReuseStrategy {
shouldDetach(route: ActivatedRouteSnapshot): boolean { return false; }
store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void {}
shouldAttach(route: ActivatedRouteSnapshot): boolean { return false; }
retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle|null { return null; }
shouldReuseRoute(future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean {
let name = future.component && (<any>future.component).name;
return future.routeConfig === curr.routeConfig || name == "NavComponent";
}
}
@NgModule({
providers: [
{
provide: RouteReuseStrategy,
useClass: CustomReuseStrategy
}]
})
export class AppModule { }
Here is your modified stackblitz, which will always reuse your NavComponent
https://stackblitz.com/edit/angular-tj5nrm?file=app/app.module.ts
Links
Route reuse Strategy explained: https://medium.com/@gerasimov.pk/how-to-reuse-rendered-component-in-angular-2-3-with-routereusestrategy-64628e1ca3eb
Default values for angular router strategy: https://github.com/angular/angular/blob/master/packages/router/src/route_reuse_strategy.ts