views:

135

answers:

2

I have some javascript that can appear on many different pages. Sometimes those pages have been accessed via a URL containing an anchor reference (#comment-100, for instance). In those cases I want the javascript to delay executing until after the window has jumped. Right now I'm just using a delay but that's pretty hackish and obviously doesn't work in all cases. I can't seem to find any sort of DOM event that corresponds to the window "jump".

Aside from the simple delay, the only solution I've come up with is to have the JS look for the anchor in the URL and, if it finds one, watch for changes in scrollTop. But that seems buggy, and I'm not 100% sure that my script will always get fired before the scrolling happens so then it would only run if the user manually scrolled the page. Anyhow, I don't really like the solution and would prefer something more event driven. Any suggestions?

Edit to clarify:

I'm not trying to detect a hash change. Take the following example:

  1. Page index.php contains a link to post.php#comment-1
  2. User clicks the link to post.php#comment-1
  3. post.php#comment-1 loads
  4. $(document).ready fires
  5. Not long later the browser scrolls down to #comment-1

I'm trying to reliably detect when step 5 happens.

+2  A: 

You can check window.onhashchange in modern browsers. If you want cross compatible, check out http://benalman.com/projects/jquery-hashchange-plugin/

This page has more info on window.onhashchange as well.

EDIT: You basically replace all anchor names with a similar linking convention, and then use .scrollTo to handle the scrolling:

$(document).ready(function () {
  // replace # with #_ in all links containing #
  $('a[href*=#]').each(function () {
      $(this).attr('href', $(this).attr('href').replace('#', '#_'));
  });

  // scrollTo if #_ found
  hashname = window.location.hash.replace('#_', '');
  // find element to scroll to (<a name=""> or anything with particular id)
  elem = $('a[name="' + hashname + '"],#' + hashname);

  if(elem) {
       $(document).scrollTo(elem, 800,{onAfter:function(){
        //put after scroll code here }});
  }
});

See http://stackoverflow.com/questions/1903574/jquery-scroll-to-anchor-when-calling-url-replace-browsers-behaviour for more info.

bryan.taylor
@bryan - The problem is not detecting a hash change, the problem is to check if, in the case that a hash is used, the window has scrolled to the proper place yet.
Peter Ajtai
@Peter Ajtai, Aaron:Might want to handle your scrolling using the .scrollTo jQ plugin. You can use the onAfter parameter to run your function calls.http://flesler.blogspot.com/2007/10/jqueryscrollto.html
bryan.taylor
I'll have to look to see if .scrollTo can handle the situation where the initial page load has an anchor in the URL. I was under the impression .scrollTo merely handled scrolling when clicking links to anchors within the current page.
Aaron
Unfortunately .scrollTo doesn't appear to handle this situation, though I'd love to be proven wrong!
Aaron
@Aaron:Actually, $.scrollTo can work with cross page links. I edited some code in my answer to show you what I'm talking about.
bryan.taylor
Good answer, but unfortunately this still doesn't suit my use case. Mainly because I'm developing this code as part of a Drupal module and I can't have the module "taking over" all hashed links in an unexpected way.
Aaron
@Aaron:Might be a good idea to delineate your limitations before you post a problem/discuss solutions :)
bryan.taylor
Fair enough. It's always a balance between too much/too little info in the question. I tried to ask a very specific question about detecting the page jump and wasn't sure where the discussion might lead.
Aaron
A: 

Seems like you could use window.onscroll. I tested this code just now:

<a name="end" />
<script type="text/javascript">
    window.onscroll = function (e) {
        alert("scrolled");
}
</script>

which seems to work.

Edit: Hm, it doesn't work in IE8. It works in both Firefox and Chrome though.

Edit: jQuery has a .scroll() handler, but it fires before scrolling on IE and doesn't seem to work for Chrome or Firefox.

Gilsham
@Gilsham - What if the window is scrolled for another reason?
Peter Ajtai
true, I guess you would have to unbind it after you've run the code oncejust add the line window.onscroll = null; after the alert and it seams fine
Gilsham
you could also check the window.pageYOffset after the page has loaded and if it is anything over 0 the page has been scrolled down
Gilsham
The problem is knowing when to check pageYOffset. document ready fires too early.
Aaron
jquery's .scroll() handler is probably the most workable solution I've seen yet. I'll have to do some testing. I'm worried about race conditions (I'm not 100% sure document ready fires before the scroll on every browser in every situation) but I can probably hobble something together.
Aaron
I'm giving Gilsham the answer because he came the nearest to answering my actual question and has outlined the general approach I will attempt to use. That said, Bryan had some helpful tips and probably has provided the most useful information for others that find themselves in a similar situation.
Aaron