I have an AngularJS app that makes a call to an API and returns a bunch of data that users can then filter by tags for greater granularity in the results. Each time a tag is clicked to filter the data, the app makes a new $http.get()
call, and the URL is modified with the appropriate query parameters so that the user can save the permalink and come back to any particular data set.
I'm trying to give the app proper history handling with window.history.pushState()
, and passing the relevant query parameters for each history object as state data. I'm using window.onpopstate
to detect when the back/forward buttons are clicked, and using that to make the new $http.get()
call with the relevant state data from the history.
For some reason, the $http.get()
function only fires on every second popstate
, and then it makes two calls. It's almost as if there's some caching going on, but I haven't been able to find the culprit. This behaviour persists in both directions, backwards and forwards, and is consistently every second event. I've verified that window.history.length
is only incremented by 1 for every tag added/removed, that the state data is being successfully sent, that new search queries are being correctly assembled, and that the request path is correct. It's just not firing. What's going on??
To illustrate, the behaviour flow looks like this:
/default
/default&tags=a
, $http.get()
returns new data/default&tags=a,b
, $http.get()
returns new data/default&tags=a,b,c
, $http.get()
returns new data/default&tags=a,b,c,d
, $http.get()
returns new datawindow.onpopstate
fires, URL is now /default&tags=a,b,c
window.onpopstate
fires, URL is now /default&tags=a,b
$http.get()
fires, sends network request for data with /default&tags=a,b,c
$http.get()
fires again, sends network request for data with /default&tags=a,b
/default&tags=a,b
loadswindow.onpopstate
fires, URL is now /default&tags=a
window.onpopstate
fires, URL is now /default
$http.get()
fires, sends network request for data with /default&tags=a
$http.get()
fires again, sends network request for data with /default
/default
loadsRelevant code snippet:
$scope.apiRequest = function(options, callback) {
// Omitted: a bunch of functions to build query
// based on user-selected tags.
// I've verified that this is working correctly.
$http.get(path)
.then(function(response) {
console.log('http request submitted');
if (callback) {
callback(response.data.response, response.data.count, response.data.facets);
console.log('data returned');
}
}, function(response) {
console.log('there has been an error');
});
}
Neither the success nor error events fire. I've tried using $http.get().then().catch()
to see if there might be something else going on, but for some reason I keep getting an error in my console that says that ...catch()
is not a valid function, which is in and of itself bewildering. Any ideas?
Thanks!
This sounds indicative of a function not cycling through the $digest
loop. In this case you may attempt to add $scope.$apply();
as the last line in your window.onpopstate
handler function to kick the $digest
cycle to execute your function call.
This article, Notes On AngularJS Scope Life-Cycle helped me to better understand the $digest
cycle and how you can force the $digest
cycle to run with $scope.$apply();
Keep in mind you want to use $scope.$apply()
sparingly but in some cases you are forced to kick off the cycle, especially with async callbacks.