Tom Ritter
Tom Ritter

Reputation: 101400

Detecting Back Button/Hash Change in URL

I just set up my new homepage at http://ritter.vg. I'm using jQuery, but very minimally.
It loads all the pages using AJAX - I have it set up to allow bookmarking by detecting the hash in the URL.

 //general functions
 function getUrl(u) {
      return u + '.html';
 }
 function loadURL(u)    {
      $.get(getUrl(u), function(r){
                $('#main').html(r);
           }
      );
 }
 //allows bookmarking
 var hash = new String(document.location).indexOf("#");
 if(hash > 0)
 {
      page = new String(document.location).substring(hash + 1);
      if(page.length > 1)
        loadURL(page);
      else
        loadURL('news');
 }
 else
      loadURL('news');

But I can't get the back and forward buttons to work.

Is there a way to detect when the back button has been pressed (or detect when the hash changes) without using a setInterval loop? When I tried those with .2 and 1 second timeouts, it pegged my CPU.

Upvotes: 63

Views: 114316

Answers (7)

balupton
balupton

Reputation: 48709

Another great implementation is balupton's jQuery History which will use the native onhashchange event if it is supported by the browser, if not it will use an iframe or interval appropriately for the browser to ensure all the expected functionality is successfully emulated. It also provides a nice interface to bind to certain states.

Another project worth noting as well is jQuery Ajaxy which is pretty much an extension for jQuery History to add ajax to the mix. As when you start using ajax with hashes it get's quite complicated!

Upvotes: 2

Drew Noakes
Drew Noakes

Reputation: 311305

The answers here are all quite old.

In the HTML5 world, you should the use onpopstate event.

window.onpopstate = function(event)
{
    alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
};

Or:

window.addEventListener('popstate', function(event)
{
    alert("location: " + document.location + ", state: " + JSON.stringify(event.state));
});

The latter snippet allows multiple event handlers to exist, whereas the former will replace any existing handler which may cause hard-to-find bugs.

Upvotes: 51

balupton
balupton

Reputation: 48709

HTML5 has included a much better solution than using hashchange which is the HTML5 State Management APIs - https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history - they allow you to change the url of the page, without needing to use hashes!

Though the HTML5 State Functionality is only available to HTML5 Browsers. So you probably want to use something like History.js which provides a backwards compatible experience to HTML4 Browsers (via hashes, but still supports data and titles as well as the replaceState functionality).

You can read more about it here: https://github.com/browserstate/History.js

Upvotes: 11

Komang
Komang

Reputation: 5064

Use the jQuery hashchange event plugin instead. Regarding your full ajax navigation, try to have SEO friendly ajax. Otherwise your pages shown nothing in browsers with JavaScript limitations.

Upvotes: 31

Nikita Koksharov
Nikita Koksharov

Reputation: 10803

Try simple & lightweight PathJS lib.

Simple example:

Path.map("#/page").to(function(){
    alert('page!');
});

Upvotes: 1

Eugene Kerner
Eugene Kerner

Reputation: 11

I do the following, if you want to use it then paste it in some where and set your handler code in locationHashChanged(qs) where commented, and then call changeHashValue(hashQuery) every time you load an ajax request. Its not a quick-fix answer and there are none, so you will need to think about it and pass sensible hashQuery args (ie a=1&b=2) to changeHashValue(hashQuery) and then cater for each combination of said args in your locationHashChanged(qs) callback ...

// Add code below ...
function locationHashChanged(qs)
{
  var q = parseQs(qs);
  // ADD SOME CODE HERE TO LOAD YOUR PAGE ELEMS AS PER q !!
  // YOU SHOULD CATER FOR EACH hashQuery ATTRS COMBINATION
  //  THAT IS PASSED TO changeHashValue(hashQuery)
}

// CALL THIS FROM YOUR AJAX LOAD CODE EACH LOAD ...
function changeHashValue(hashQuery)
{
  stopHashListener();
  hashValue     = hashQuery;
  location.hash = hashQuery;
  startHashListener();
}

// AND DONT WORRY ABOUT ANYTHING BELOW ...
function checkIfHashChanged()
{
  var hashQuery = getHashQuery();
  if (hashQuery == hashValue)
    return;
  hashValue = hashQuery;
  locationHashChanged(hashQuery);
}

function parseQs(qs)
{
  var q = {};
  var pairs = qs.split('&');
  for (var idx in pairs) {
    var arg = pairs[idx].split('=');
    q[arg[0]] = arg[1];
  }
  return q;
}

function startHashListener()
{
  hashListener = setInterval(checkIfHashChanged, 1000);
}

function stopHashListener()
{
  if (hashListener != null)
    clearInterval(hashListener);
  hashListener = null;
}

function getHashQuery()
{
  return location.hash.replace(/^#/, '');
}

var hashListener = null;
var hashValue    = '';//getHashQuery();
startHashListener();

Upvotes: 1

micahwittman
micahwittman

Reputation: 12476

jQuery BBQ (Back Button & Query Library)

A high quality hash-based browser history plugin and very much up-to-date (Jan 26, 2010) as of this writing (jQuery 1.4.1).

Upvotes: 12

Related Questions