Is there a way to call history.pushState()
without angular going into an infinite digest loop?
I'm trying to migrate my app from backend routing to frontend routing and all the stackoverflow posts/google resources don't seem to have an answer.
In an HTML document, the history. pushState() method adds an entry to the browser's session history stack.
But this function is not intended to reload the browser. All the function does, is to add (push) a new "state" onto the browser history, so that in future, the user will be able to return to this state that the web-page is now in.
In an HTML document, the history.pushState () method adds an entry to the browser's session history stack.
Note that pushState () never causes a hashchange event to be fired, even if the new URL differs from the old URL only in its hash. This creates a new browser history entry setting the state, title , and url . Found a problem with this page?
In a sense, calling pushState () is similar to setting window.location = "#foo", in that both will also create and activate another history entry associated with the current document. But pushState () has a few advantages:
If you pass a state object whose serialized representation is larger than this to pushState (), the method will throw an exception. If you need more space than this, you're encouraged to use sessionStorage and/or localStorage . Most browsers currently ignore this parameter, although they may use it in the future.
I recently encountered a variation of this problem myself and none of the answers here worked for me in isolation. history.pushState
was defined, but only worked if called from the console. I was able to come up with a solution by consolidating a few of the answers here. Here is the code I used to solve this problem:
// Configure $locationProvider html5Mode
app.config(['$locationProvider', function($locationProvider) {
$locationProvider.html5Mode({ enabled: true, requireBase: false, rewriteLinks: false });
}]);
// In controller
$window.history.pushState(null, 'Page Title', '/some_new_url');
I'm running Angular 1.5.5.
This is what we do in an Angular 1.2.16 app based on this github comment: https://github.com/angular/angular.js/issues/3924#issuecomment-48592773
$location.url(myNewUrl);
$location.replace();
$window.history.pushState(null, 'any', $location.absUrl());
This code is part of a controller. I'm using it to add a query param to the url without wanting to reload the page. It works in our case.
Use the rewriteLinks option on the $locationProvider html5Mode object:
pageModule.config(function($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false,
rewriteLinks: false
});
});
Afterwards, you should be able to use the $location service properly, such as:
this.$location.path("/mynewpath");
I was able to come up with a solution that works with angular 1.2.15.
The gist of it is to add a target
attribute to each link and then use the $location
service to change the location.
Based on the current angular code, anchor tags that have a target attribute are ignored (note that this solution may eventually break).
To do this, ensure this javascript runs before angular:
// prevent angular from taking over link clicks until we have frontend routing
$(document.documentElement).on("click","a",function(event) {
var elem = $(this), target = elem.attr("target");
if(!target) {
elem.attr("target","_self");
setTimeout(function() {
elem.removeAttr("target");
});
}
});
After that, configure your location provider to use html5mode:
angular.module("App", ["App.controllers"]).config([
"$locationProvider", function($locationProvider) {
if (history.pushState) {
$locationProvider.html5Mode(true);
}
}
]);
Now, in your controller, inject the location service and use it normally:
angular.module("App.controllers",[]).controllers("SomeController", ["$scope", "$location", function($scope,$location){
$scope.updateLocation = function() {
if (history.pushState) {
$location.path("/new/path/here");
}
};
}]);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With