First off I want to say that AngularJS is fantastic, and I am really enjoying developing with it. Thank you Google and the Angular team for providing such a great framework.
So I am building a search page that takes search criteria from the user, executes the search according to the criteria, and renders the result via a template. I need for each search to push a new URL onto the history so the user can use the back and forward buttons to navigate through their searches. I considered using the RESTy way that AngularJS supports with tokens in the path, but that doesn't work well for search. My search parameters include query, filters, page and sort. Path routing requires that all of the parameters be ordered in a specific order, which is not ideal. I would like to support the parameters in any order. Therefore I have decided that placing the parameters in the search fragment, or the query string, is the way to go. Also, this seems to be the standard way things are done with search. If anyone has ideas about this or suggestions for improvement please share.
So my URL format is like this: /search?q={query}&filters={filters}&p={page}&sort={sort}
All of the parameters are optional and the parameter order does not matter.
After a search is triggered I can update the query string by calling $location.search(). This works as expected. However I need to respond to changes to movements forward and backward in the history. I could not find a good way to listen for history events with AngularJS, so the best way I could determine to do that was to watch $location.search() with my controller. The problem is that the watch is only firing when the page first loads, and not anytime after that. Not when it changes due to my code after a search is triggered. Not when the back or forward buttons are clicked.
I have the following route:
$routeProvider
.when('/search', {
templateUrl: '/assets/html/searchView.html',
controller: SearchCtrl,
reloadOnSearch: false // do not reload controller when querystring changes
})
The controller and template are coupled to an <ng-view/> in the page. The reloadOnSearch is disabled to prevent AngularJS from reloading the controller and template every time the query string changes, which happens every time a search is triggered, because of my code described above.
To watch $location.search, I have the following in my controller:
$scope.$watch('$location.search()', function(newQs, oldQs) { ... });
As I said, this watch is only being fired on the initial load of the page. This means I can't handle history state changes. Am I doing something wrong? Is there another way to monitor the history? I suppose it is possible that the reloadOnSearch:false in my route is causing this, but I would expect that would only affect the reloading of the controller and not whether or not watches on $location.search() fires. Is this a bug? Is there a fundamental problem in my approach?
Thanks for reading and any help you can provide,
Mark