57

I'm using the hash to load content dynamically. To make the back button work I am capturing hash changes. However sometimes I need to change the hash without triggering the hash changed function (eg, when the page was redirected server side and I need to update the hash once the content has returned.)

The best solution I have come up with is to unbind the hashchange event, make the change and then rebind it. However, as this happens asynchronously, I am finding that it rebinds too quickly and still catches the hash change.

My solution at the moment is very poor: Rebinding in a setTimeout. Does anyone have a better idea?

    $(window).unbind( 'hashchange', hashChanged);
    window.location.hash  = "!" + url;
    setTimeout(function(){
        $(window).bind( 'hashchange', hashChanged);
    }, 100);


Edit:
Amir Raminfar's suggestion prompted me to a solution that does not require a timeout. I added a class variable

_ignoreHashChange = false;

When I want to change the hash silently I do this:

_ignoreHashChange = true;
window.location.hash  = "!" + url;

and the hash changed event does this :

function hashChanged(event){
    if(_ignoreHashChange === false){
        url = window.location.hash.slice(2);
        fetchContent(url);
    }
    _ignoreHashChange = false;
}
SystemicPlural
  • 5,629
  • 9
  • 49
  • 74
  • 4
    a nice, simple solution, you should make it an answer – Peter Sep 19 '12 at 09:19
  • 1
    The only thing left is to check that new hash is not equal the old one before setting _ignoreHashChange=true; – Kasheftin Mar 23 '13 at 13:32
  • 1
    You might want to check out Cowboy's BBQ library which gives you fine control over all things Back and Hashchange: http://benalman.com/code/projects/jquery-bbq/docs/files/jquery-ba-bbq-js.html – hybernaut Nov 05 '10 at 14:26
  • Where do you define the hashChanged event? – Miguel Stevens Feb 05 '15 at 13:07
  • It may be good to store the original value of _ignoreHashChange and reset to that. e.g. `var _ = _ignoreHashChange; [...]; _ignoreHashChange = _` – Wes Turner Apr 22 '15 at 11:35

2 Answers2

29

You could use history.replaceState and append the hash, to replace the current URI without triggering the hashchange event:

var newHash = 'test';

history.replaceState(null, null, document.location.pathname + '#' + newHash);

JSFiddle example

Tim
  • 2,805
  • 25
  • 21
  • 4
    `history.replaceState` also does NOT push the hashchange into history as well, but if you want that, you can use `history.pushState` ;) – qdev Dec 20 '17 at 22:23
6

You can have a function like this:

function updateHash(newHash){
  ...
  oldHash = newHash
}

then in your setTimeOut you need to do

function(){
  if(oldHash != currenHash){
    updateHash(currenHash);
  }
}

So now you can call update hash manually and it won't be triggered by the event. You can also have more parameters in updateHash to do other things.

By the way, have you looked at the jquery history plugin? http://tkyk.github.com/jquery-history-plugin/

Amir Raminfar
  • 33,777
  • 7
  • 93
  • 123