Do you want to request a _feature_ or report a _bug_?
bug
What is the current behavior?
By setting a state with $location.state() angular still adds/refreshes a session history.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://plnkr.co or similar (template: http://plnkr.co/edit/tpl:yBpEi4).
To reproduce this you should just change url 100+ times without refreshing the page, on specific OS and Browser.
What is the expected behavior?
By setting $location.state() history should not be updated.
What is the motivation / use case for changing the behavior?
In the last version of safari 9.1.1 maximum history refresh/push is 100, and for application that are updating url without refreshing the application it throw error:
Error: SecurityError: DOM Exception 18
pushState@[native code]
and
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.
Angular version: 1.4.0
OS: Apple operating systems
Browser: Safari 9.1.1
The code that is generating this issue, is the same in the last versions of angular 1
Other information (e.g. stacktraces, related issues, suggestions how to fix)
Function:
function stripHash(url) {
var index = url.indexOf('#');
return index == -1 ? url : url.substr(0, index);
}
checks only if hash is present and is not covering the case when I'm using $locationProvider.html5Mode(true); and / instead of #/, overwise returns the whole url and this if statement passes even if it's the same state but different params in url:
if ($sniffer.history && (!sameBase || !sameState)) {
history[replace ? 'replaceState' : 'pushState'](state, '', url);
cacheState();
// Do the assignment again so that those two variables are referentially identical.
lastHistoryState = cachedState;
}
Could you post a reproduction (e.g. a live demo on CodePen, Plnkr etc or if not possible a small code sample that we can run serve and run locally) ?
Does it affect other browsers ?
http://plnkr.co/edit/UOmAFNZX4O1Y8iUS4Dzh?p=preview here is a primitive example.
The error I described above, reproduces only on Safari version 9.1.1.
But the issue: when html5 is enabled and working without # in url history is updated even if $location.state() is set and it's the same for every change.
I'm using ui.router but $location.state() is set in my project. After debugging in angular.js I observed that the problem is in the code i wrote in the issue under this paragraph:
_Other information (e.g. stacktraces, related issues, suggestions how to fix)_
@AScripnic, I don't see anything unexpected in your example (using uiRouter).
The URL changes and as a result we are calling window.history.replaceState(...) (because uiRouter hs called $location.replace()).
This is all expected behavior (as far as I can tell). Also, note, that there is no $location.state() involved.
I'm using ui.router but $location.state() is set in my project.
I can't speak about your use of $location.state(), because I haven't seen it :smiley:
By setting $location.state() history should not be updated.
Why not ? According to the docs, $location.state() will:
Change the history state object when called with one parameter and return
$location. The state object is later passed topushStateorreplaceState.
emphasis mine
After debugging in angular.js I observed that the problem is in the code i wrote in the issue under this paragraph
What you describe in the last paragraph of your initial post is expected behavior. It is independent of HTML5 vs HashBang mode - this is a lower level API, where we only care about what happened to the actual URL in the browser's address bar (what it means to Angular is irrelevant).
It might help to show the actual code that you are using in your project and you think makes Angular behave incorrectly and describe the actual vs expected behavior of the code.
With the info we have so far, everything seems to work as expected.
Now, the fact that Safari 9.1.1 only allows 100 calls to history.pushState/replaceState is very unfortunate (even if it's by design), but I am not sure what we can do about it.
@petebacondarwin, do you think it would make sense to try and detect Safari 9.1.1+ and treat it as if history is unavailable ?
I'm really sorry for forgetting about $location.state, i was worrying about DOM error more, here is an updated version: http://plnkr.co/edit/eb5pyMZMDuB52f9u6iBP?p=preview .
By analyzing this code:
if ($sniffer.history && (!sameBase || !sameState)) {
history[replace ? 'replaceState' : 'pushState'](state, '', url);
cacheState();
// Do the assignment again so that those two variables are referentially identical.
lastHistoryState = cachedState;
}
I supposed there should be a method to ignore history changes, and i was trying to find a way to ignore it, to make it run on safari.
Is there any possibility to add this functionality, about ignoring history?
Do you mean a way to act as if window.history is not available ? I'm afraid there is no "official" way to do this, but there might be a couple of "unofficial" ways (which you didn't hear from me).
Obviously, overwriting window.history to a falsy value is out of question, because a whole lot other things could break as a result.
You can decorate the $sniffer service and set $sniffer.history to false:
.decorate('$sniffer', function decorateSniffer($delegate) {
$delegate.history = false;
return $delegate;
})
The problem with that, is that $sniffer is a private, undocumented, not-intended-to-be-used-by-developers service, meaning it's API might break without any notice, even between patch releases.
(I don't consider it very likely to happen any time soon, but theoretically it's possible.)
@gkalpak Thank you for your time and for the help. I got answers to all my questions.
And thank you very much for methods you gave me to solve the problem.