Angular — Replacing Page Layout in Child Routes
In the applications I’ve worked on recently, a common requirement has been to create hierarchical pages where each child page completely replaces its parent. For these scenarios, I couldn’t figure out how to tell the router to do this, and so about a year ago or so I asked the question on Stack Overflow.
The common answer there (and on similar questions) is to not setup the routes hierarchically, and instead have them all at the same route level. This works, however it’s not very clean: if you have guards, for example, you’d need to ensure you’ve included them in each child route, and as you go farther and farther down the chain you’ll end up with quite a bit of duplicate code.
I recently watched an AngularMIX conference presentation by Alex Rickabaugh regarding ways to use template directives, and the example use case seemed very similar to this scenario.
Based on this, I’ve created a basic implementation to solve this page layout problem and the demo can be seen here: https://stackblitz.com/edit/angular-routing-page-layout
In the demo, our layout component (PageContainerComponent
) has two ng-container
s: one for a header and one for content:
We then create a directive per container (PageContainerHeaderDirective
and PageContainerContentDirective
) which will be responsible for handling our page specific templates:
As the router creates the page components, the template directives will add the templates to the appropriate stack (header or content) in the page container. If the user leaves a route, the page component will be destroyed, our our template directive will remove the template from the stack.
The resulting pages then end up looking like so:
For any route that will have a child route, the template will need to contain a <router-outlet></router-outlet>
. It’s important the router-outlet
is placed at the end of the template: if the router-outlet
is before our template directives then it’s possible the templates won’t be added in the correct order to the stack.
As a disclaimer, the version I currently have implemented is more complicated than this (it uses a service to facilitate the communication opposed to the directives injecting in the container component), so this concept may not work in every scenario: I plan to switch over to this implementation and will update the article if I run into any issues.
If anyone has any suggestions for improving the concept, please let me know: for example I think if the user landed in the application at a child route, the page would end up creating and destroying the views of the parent routes needlessly. I would think there should be a way to cache the views for reuse opposed to clearing/recreating as well.