Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 0656484

Browse files
committed
fix($browser): don’t use history api when only the hash changes
IE10/11 have the following problem: When changing the url hash via `history.pushState()` and then reverting the hash via direct changes to `location.href` (or via a link) does not fire a `hashchange` nor `popstate` event. This commit changes the default behavior as follows: Uses `location.href`/`location.replace` if the new url differs from the previous url only in the hash fragment or the browser does not support history API. Use `history.pushState`/ `history.replaceState` otherwise. Fixes #9143 Closes #9406
1 parent f3539f3 commit 0656484

File tree

3 files changed

+31
-1
lines changed

3 files changed

+31
-1
lines changed

src/ng/browser.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,13 @@ function Browser(window, document, $log, $sniffer) {
153153
// setter
154154
if (url) {
155155
if (lastBrowserUrl == url) return;
156+
var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
156157
lastBrowserUrl = url;
157-
if ($sniffer.history) {
158+
// Don't use history API if only the hash changed
159+
// due to a bug in IE10/IE11 which leads
160+
// to not firing a `hashchange` nor `popstate` event
161+
// in some cases (see #9143).
162+
if (!sameBase && $sniffer.history) {
158163
if (replace) history.replaceState(null, '', url);
159164
else {
160165
history.pushState(null, '', url);

src/ng/location.js

+3
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,9 @@ function $LocationProvider(){
720720

721721
if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
722722
if ($location.$$parseLinkUrl(absHref, relHref)) {
723+
// We do a preventDefault for all urls that are part of the angular application,
724+
// in html5mode and also without, so that we are able to abort navigation without
725+
// getting double entries in the location history.
723726
event.preventDefault();
724727
// update location manually
725728
if ($location.absUrl() != $browser.url()) {

test/ng/browserSpecs.js

+22
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,17 @@ describe('browser', function() {
445445
expect(locationReplace).not.toHaveBeenCalled();
446446
});
447447

448+
it('should set location.href and not use pushState when the url only changed in the hash fragment to please IE10/11', function() {
449+
sniffer.history = true;
450+
browser.url('http://server/#123');
451+
452+
expect(fakeWindow.location.href).toEqual('http://server/#123');
453+
454+
expect(pushState).not.toHaveBeenCalled();
455+
expect(replaceState).not.toHaveBeenCalled();
456+
expect(locationReplace).not.toHaveBeenCalled();
457+
});
458+
448459
it('should use location.replace when history.replaceState not available', function() {
449460
sniffer.history = false;
450461
browser.url('http://new.org', true);
@@ -456,6 +467,17 @@ describe('browser', function() {
456467
expect(fakeWindow.location.href).toEqual('http://server/');
457468
});
458469

470+
it('should use location.replace and not use replaceState when the url only changed in the hash fragment to please IE10/11', function() {
471+
sniffer.history = true;
472+
browser.url('http://server/#123', true);
473+
474+
expect(locationReplace).toHaveBeenCalledWith('http://server/#123');
475+
476+
expect(pushState).not.toHaveBeenCalled();
477+
expect(replaceState).not.toHaveBeenCalled();
478+
expect(fakeWindow.location.href).toEqual('http://server/');
479+
});
480+
459481
it('should return $browser to allow chaining', function() {
460482
expect(browser.url('http://any.com')).toBe(browser);
461483
});

0 commit comments

Comments
 (0)