Friday, August 22nd, 2008
Emulating onhashchange without setInterval
<p>IE 8 has an onhashchange event, and Ajax history / bookmark management has been a long time problem of choice for developers.Zach Leatherman has revisited the problem and has another solution that doesn’t require setInterval to check on the location.
- On initialization, we load an iframe onto the page that is positioned absolutely at -500px,-500px so the user can’t see it. It is a skeleton page that only needs cross browser code to add an “
onscroll” event, and to be able to calculate the scrolled position of the iframe itself. For my example, I use jQuery and the dimensions plugin to accomplish this, but it could easily be trimmed down to only the bare essentials (or ported to a different library). - To add an AJAX history entry into the browser’s history under an assigned hash string, we first add a
<a name="hashString">hashString</a>to the<body>tag of the iframe. Using css to increase the size of the a tag proportional to the iframe’s height, we can guarantee scrolling will happen. - Then, we change the
location.hashof the iframe to point to that<a>tag. This will scroll the iframe to the content, and create a new entry in the browser’shistoryobject. - Inside the iframe, we have our
onscrollevent that fires when the scrolling in the previous step took place. (Minor IE-related workaround: The browser’shistoryobject is changed, but the hash property doesn’t when attempting to read it later. Instead, we find the<a>that matches up with the scrollY/pageOffsetY property inside of the iframe, and retrieve the matching hash from the<a>tag.)
The solution gives you history management and back button support in one fell swoop, with the side effect of not having bookmarkability (since the iframe is updated).








hot, what else can i say
It immediately breaks when you resize text. I’ll stick with a timer thanks.
I wrote a history script a few years ago that does something similar, with bookmarking:
http://bloomd.home.mchsi.com/newhist/demo
One fun advantage over other history scripts it has is that it can tell the index in the history, as well as the hash value. So you can have two pages in the same session with the same hash value, and be able to distinguish the two (for purposes such as cacheing scroll position, etc).
It’s really, really hacky though. It actually loads the page’s content in a position:fixed iframe. And it doesn’t work in Opera :-(.
Hey Dean,
I have a lot of respect for the work that you’ve done, but I think that concentrating on that one point of failure misses the beauty of the approach.
This is a cross browser bookmarking script that relies on almost nothing but standard browser behavior: that linking to a #name will jump to that name on the page and create a new history entry.
Removing the text inside of the div’s created inside of the iframe would fix your problem, no?
Regards, Zach
Also, you’d have to resize your text to gargantuan proportions to actually break this approach. But I’ll update the page with a fix.
@Zach, sorry to be a wet blanket. If you can get it working with resized text then I might reconsider. :-)
@Dean, I’ll work on it later tonight when I’m not on company time. I’ll update the post on my page when I’ve got it working. It’s good to stay hydrated, just try not to get soaked.
You could fix the text-resize issue with some CSS, I think.
a {
display:block;
height:50px;
overflow:hidden;
}
Since the target element is a fixed size (the size should be greater than the height of the iframe, I assume), scrolling will always happen and text size won’t matter.
Hey quixote and Dean,
It doesn’t even need text in the a tags inside of the i-frame. You can get the current hash from the name attribute of the currently scrolled i-frame.
I’ve updated the script on my page, if you want to check it out.
Thanks,
Zach
Timer is least problematic, n most easy..
y nt use this!!
if ((‘onhashchange’ in window) || (‘onhashchange’ in document))
window.onhashchange = doSomething;
else
window.setInterval(“doSomething()”,200);