Search code examples
javascripthtmlasynchronousoperabrowser-history

Change history after async ajax request on Opera 12


Introduction

In an older version of Opera (Opera/9.80 (Macintosh; Intel Mac OS X 10.10.3) Presto/2.12.388 Version/12.16) there is a problem with history when update the document.location.hash on an ajax request callback.

Steps to reproduce:

  • listen to hashchange and log document.location.hash and history.length
  • change document.location.hash
  • create a GET request to a json
  • handle the GET ajax response and change document.location.hash
  • wait 5 seconds and change document.location.hash
  • click on the a link on the page that changes document.location.hash

The code:

// listen to hash changes
$(window).on('hashchange', function() {
  console.log("Updated hash: ", document.location.hash);
  console.log("history.length: ", history.length);
});
var updateHash = function(hash) {
  document.location.hash = hash;
};
// set the first route
updateHash('#start');

// do async request and change route
promise = $.get('http://beta.json-generator.com/api/json/get/PumsGq6');
promise.done(function() {
  updateHash('#done_async');
});

// wait for 5 seconds and change route
setTimeout(function() {
  updateHash('#complete_timeout');
}, 5000);
<!DOCTYPE html>
<html>

<head>
  <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
  <meta charset="utf-8">
  <title>History change</title>
</head>

<body>
  <a href="#page">set page</a>
</body>

</html>

What's the result in Chrome and Firefox:

Updated hash:  #start
history.length:  2
> XHR finished loading: GET "http://beta.json-generator.com/api/json/get/PumsGq6"
Updated hash:  #done_async
history.length:  3
Updated hash:  #complete_timeout
history.length:  4
Updated hash:  #page
history.length:  5

What's the problem —> Opera 12:

Updated hash: , #start
history.length: , 2
Updated hash: , #done_async
history.length: , 2
Updated hash: , #complete_timeout
history.length: , 3
Updated hash: , #page
history.length: , 4

As can be seen in the console output after an async request the browser history is not changed, although the url/hash is updated correctly. The setTimeout is just to validate that the history can be changed in a not synced fashion.

This is causing navigation issues as I can't go back to a point that does not exists in history.


Solution

  • Although I don't have a full explanation for this it was solved by using jQuery ^1.8.3.