Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the hashchange event to work in all browsers (including IE7)

I have some code (written by another developer) that is doing AJAX page loading inside of WordPress (e.g. no page reloads) when you click a nav item, AJAX refreshes the primary content area. My problem is that it's broken in IE7 and I have no idea where to start in terms of debugging.

The original opening lines were

var queue = 0;

$('document').ready(function() {
    window.addEventListener("hashchange", hashChange, false);

    // Define window location variables
    var windowHost = window.location.host,
        windowHash = window.location.hash,
        windowPath = window.location.pathname;

But I changed them to make the addEventListener conditional on the basis of whether that method was present or not. Some research told me that the method is not available in older versions of IE (e.g. 7 in my case). Also, the IE7 debug console was identifying that as an unavailable method, so that's pretty clear. I rewrote the lines as follows, but the code is still not working:

var queue = 0;

$('document').ready(function() {
    if(window.addEventListener) {
        window.addEventListener("hashchange", hashChange, false);
    }
    else if (window.attachEvent) {
        window.attachEvent("hashchange", hashchange, false);    
    }
    // Define window location variables
    var windowHost = window.location.host,
        windowHash = window.location.hash,
        windowPath = window.location.pathname;

The full original script can be viewed in this pastebin: http://pastebin.com/Jc9ySvrb

like image 714
Brian Avatar asked Feb 18 '12 08:02

Brian


2 Answers

  • attachEvent requires events to be prefixed with on.
  • You've different capitalizations for the method. Change hashchange in attachEvent tohashChange to get the event to work in IE8.
  • Use the suggested implementation to support the hashchange implementation for IE7- and other old browsers.

I have created a cross-browser implementation, which adds the hashchange feature to browsers, even those who do not support it. The fallback is based on the specification.

//function hashchange  is assumed to exist. This function will fire on hashchange
if (!('onhashchange' in window)) {
    var oldHref = location.href;
    setInterval(function() {
        var newHref = location.href;
        if (oldHref !== newHref) {
            var _oldHref = oldHref;
            oldHref = newHref;
            hashChange.call(window, {
                'type': 'hashchange',
                'newURL': newHref,
                'oldURL': _oldHref
            });
        }
    }, 100);
} else if (window.addEventListener) {
    window.addEventListener("hashchange", hashChange, false);
}
else if (window.attachEvent) {
    window.attachEvent("onhashchange", hashChange);    
}

Note: This code is useful for one hashchange event. If you want to add multiple hashchange handlers, use the following method.
It defines two functions, addHashChange and removeHashChange. Both methods take a function as an argument.

(function() {
    if ('onhashchange' in window) {
        if (window.addEventListener) {
            window.addHashChange = function(func, before) {
                window.addEventListener('hashchange', func, before);
            };
            window.removeHashChange = function(func) {
                window.removeEventListener('hashchange', func);
            };
            return;
        } else if (window.attachEvent) {
            window.addHashChange = function(func) {
                window.attachEvent('onhashchange', func);
            };
            window.removeHashChange = function(func) {
                window.detachEvent('onhashchange', func);
            };
            return;
        }
    }
    var hashChangeFuncs = [];
    var oldHref = location.href;
    window.addHashChange = function(func, before) {
        if (typeof func === 'function')
            hashChangeFuncs[before?'unshift':'push'](func);
    };
    window.removeHashChange = function(func) {
        for (var i=hashChangeFuncs.length-1; i>=0; i--)
            if (hashChangeFuncs[i] === func)
                hashChangeFuncs.splice(i, 1);
    };
    setInterval(function() {
        var newHref = location.href;
        if (oldHref !== newHref) {
            var _oldHref = oldHref;
            oldHref = newHref;
            for (var i=0; i<hashChangeFuncs.length; i++) {
                hashChangeFuncs[i].call(window, {
                    'type': 'hashchange',
                    'newURL': newHref,
                    'oldURL': _oldHref
                });
            }
        }
    }, 100);
})();
// Usage, infinitely many times:
addHashChange(function(e){alert(e.newURL||location.href);});
like image 197
Rob W Avatar answered Sep 20 '22 08:09

Rob W


attachEvent takes on two params:

bSuccess = object.attachEvent(sEvent, fpNotify)

[And is needed for all versions of IE below IE9! :( See MDN reference ]

This could work:

if(window.addEventListener) {
    window.addEventListener("hashchange", hashChange, false);
}
else if (window.attachEvent) {
    window.attachEvent("onhashchange", hashchange);//SEE HERE...
    //missed the on. Fixed thanks to @Robs answer.
}

Of course if it is possible, you should just use JQuery, since it encapsulates all this for your.

And as always there is a plugin out there: http://benalman.com/projects/jquery-hashchange-plugin/

like image 20
gideon Avatar answered Sep 21 '22 08:09

gideon