Angular Design pattern: State management with URL params
The suggested mechanism of dealing with state in Angular is:
- Pass the state to a component from previous using
@Input
directive. OR - Maintain the state in a store which is decoupled from components. You can read a little about this state management using Redux here. Maintaining state in a store is preferable as compared to passing state around through components. A store has the advantage that the state does not depend on any of the component interactions and increases the Unit testing ability of your application.
Use URL parameters to maintain Angular state
My suggestion is to instead go back to the good-old URL query parameters to maintain state when moving from one component to other. Some example URLs would be:
/posts/1 /posts/1?showFullPost=1
There is a fairly big list of advantages that come along with this setup:
- No hidden state in the site. We simply reload the page to get back to the same place. Similarly, a user can open the URL in a new tab and it still works.
- Easier manual as well as automated testing. Since each component only depends on the URL params, we can simply test each component with Integration tests. Other alternative is to go through whole flow to run any E2E tests making tests slower and harder to isolate.
- A truly modular application. One team can develop on one page without affecting anyone else.
- Cross-app re-usability. This is one of the most important uses I have found. If you are working on anything which is a big project, you would inevitably end up with multiple frameworks due to various reasons. And thus a need to work cross-framework. URL parameters come and save the day allowing you to invoke a component of your choice directly from a different platform. For example, a simple HTML button on your WordPress page leading you to an Angular form.
Of course there are some disadvantages which would arise when designing a complex web application:
- Complex objects can’t be shared from one page to another. The possible solution is to always get data from server instead of sending it from one component to other increasing the network calls but maintaining simplicity.
- It might not be always possible if the data is stateful. Eg: Session tokens, transaction tokens etc. These still need to be handled in the conventional fashion. Again there would be sensitive data like session IDs which should continue to belong to Cookies or the application’s store.
-
Ugly URLs at times. For example, a google search result for URL query parameters returns this URL:
https://www.google.com/search?source=hp&ei=aVf2W-7uFYeEvQT3iJ-ACA&q=url+query+parameters&btnK=Google+Search&oq=url+query+p&gs_l=psy-ab.3.0.0i67j0l2j0i67j0l6.55.1392..2227...0.0..0.248.2080.0j8j4......0....1..gws-wiz.....0..35i39j0i131j0i131i20i263.hqLNtDbTQYY
Is it against Angular principles?
I like to think that we are going towards modularization thus moving in the right direction which was what was envisioned by Angular team to begin with.
Technical implementation
The current technical implementation is straightforward.
constructor(private activatedRoute: ActivatedRoute) { this.activatedRoute.queryParams.subscribe(params => { this.x = params['x']; }); }
This is an issue on Angular tracking support for parameters which can work as @Input
.
Would love to hear other opinions of using URL params to contain state. Have you found further disadvantages as your site becomes more complex?
I like to store at least gui state this way. It’s good to have bookmarks working as users expect.