Passing Data to Any Angular Component on Router Navigation
There are several different ways to pass data from one component to the next. We will briefly discuss a few of these options and then implement passing data from a component you’re navigating away from to the component you navigated to using router NavigationExtras
. Finally, we’ll end the discussion with a brief list of considerations you should make before choosing one approach over another.
A Simple Component Hierarchy
A common way to pass data to a component is via the @Input()
decorator. This works well with a simple parent/child relationship. In Figure 1, we would use A.component.html to pass data into the @Input()
property defined on B.component.ts.
A Less Ideal Component Hierarchy
Suppose you wanted to pass data from component A to component E from the hierarchy in figure two. We could define @Input()
properties to B, C, D, and E. If B, C, and D also care about the data, this solution might work for you. But it does become less manageable, especially if you wanted E to change the data and A to know about it, as we would need a tangled mess of propagating the change back to A via @Output()
.
A Messy, Complicated Component Hierarchy
In Figure 3, it is impossible to only use @Input()
to pass data from A to E. You could potentially use a combination of @Output()
and @Input()
along with utilizing the ngOnChanges
lifecycle hook. Still, I will leave the details to a curious reader but be weary of using this solution as it has the same pitfalls as the solution to Figure 2, only more complex!
The Service Approach
To get the data from A to E (in reference to Figures 2 and 3), we could potentially create an Angular service that stores the data. Then we would push changes from A into the service and subscribe to changes in E. But for some use cases, this would introduce unnecessary complexities, especially if we are not using that service data anywhere else in the web app. Fortunately, another option may prove to be the simpler solution for one-off exchanges of data between more complicated component hierarchies!
Utilizing NavigationExtras
In component A, we can set NavigationExtras.state to the data we want to pass to component E. Then we pass navigationExtras
along with the URL of the component to router.navigate()
.
Then in ngOnInit
of component E, we get the current navigation and grab the data we passed through the router with history.state
. We’re now free to use this data however we need to in component E.
The router has passed data from A to E via NavigationExtras.state
but does not show up in the URL. This is an extremely useful feature to get a little bit of data from one component to the next on navigate without regard to the component hierarchy. But do not rely on this to persist data throughout your web app! As soon as the user refreshes the page, the router state is gone.
Final Thoughts
Angular is an extremely feature-dense front-end framework with many paths to the same solution. Every solution is context-dependent. In practice, a solution that works in one context might not necessarily work in another. Try to keep these questions in mind when determining how you should pass data in your web app.
- Will this data be used in multiple places?
- If so, hosting the data in your service layer might be a good approach.
- What does the component hierarchy look like?
- What functionality within these components is most likely to change?
- What is the level of effort required to create and maintain this solution?
- Is there an existing pattern already established in your web app?
For a feature I recently worked on, the data wasn’t used in multiple areas and didn’t have a simple component hierarchy. I just needed that data to be passed from the component I’m navigating away from to the component I’m navigating to. I didn’t care about losing the data on refresh, so utilizing the navigation state was the best option for me.