Providing State-Transformation Triggers Using $location In AngularJS
When I first started using routes, nested views, and deep linking in AngularJS, I thought that everything in the URL had to be related to the route. As such, I rarely ever used the $location service, except to change the path in order to trigger a new route-change event. Over time, however, I came to embrace the fact that the $location service was a wonderful way to provide state-transformation information for the target View after the route had changed successfully.
When it comes to the URL in a single-page AngularJS application, the URL, while behind a hash (or hash-bang), mimics a normal URL. Meaning, it has a path, a search query, and a fragment (or hash) in the same way that a normal URL does. And, while the entire URL technically represents the state of your application, I have started to think about different components of the URL in different ways.
NOTE: Html5 mode blurs this line; but, I don't have any personal experience with it yet.
Right now, I think about the route - the path - as defining which View(s) will be rendered. In essence the route defines the location of the user within the landscape of the application. The query string, on the other hand, provides additional information - often optional - about the state and/or state-transformation of the rendered View.
Before I embraced this dual-purpose URL mentality, I used to jump through a lot of unnecessarily complex hoops in order to get transient state information to pass from one View to the next. This typically required me to lean very heavily on shared parent Scopes, creating tightly coupled controllers. By moving this information into the search query of the URL, it removed a lot of cruft, helped decouple the controllers, and made the code much easier to understand.
I didn't really know what kind of a demo would exemplify this philosophy; so, rather than trying to be too relevant, I just created a demo that used both the route [path] and the query string to help update the view independently. In the following code, the route defines the location of a maker while the query string defines the look and feel of the marker. I felt like this mapped decently to app-location vs. view-state.
As you can see, when the $location changes, we can respond to the $locationChangeSuccess event. And, when the route changes, we can respond to the $routeChangeSuccess event. Keep in mind that there will be a lot of cross-over in these two events; since the route is driven by a subset of the URL components, every route change will also result in a location change. The reverse, however, is not always true - we can have a location change that does not result in a route change.
In AngularJS, there's so much emphasis on storing information in services and controllers, it's easy to forget that the URL can contain valuable information about the state of the page. Both the route and the query string can work together to determine not only which View to render but, how that view should behave once it is rendered.
Want to use code from this post? Check out the license.
I added a follow-up post to this:
I thought this post didn't really capture the difference in use-case for the route vs. location query string. The follow-up post should help clarify my thoughts on the matter.