4

I have a bit of javascript that smooth scrolls to any clicked #anchor-id (adaptation of this). For certain pages it throws a $target.offset(...) is undefined error, and stops working, and I don't understand why.

I have done some testing and it seems to be correlating to the length of the page, as far as I can tell. Keeping all variables the same, only varying the amount of content, the bug occured (on the exact same page).

The weird thing is that I haven't been able to reproduce this effect on jsfiddle, it works fine over there, for every length. Does anyone know how to troubleshoot this bug? What could be the cause of it?


This is the javascript I'm using (I link to it at the bottom of every page, right before the </body> tag and immediately after loading jquery 1.10.2):

$(document).ready(function() {
  function filterPath(string) {
  return string
 .replace(/^\//,'')
 .replace(/(index|default).[a-zA-Z]{3,4}$/,'')
 .replace(/\/$/,'');
  }
  var locationPath = filterPath(location.pathname);
  var scrollElem = scrollableElement('html', 'body');
  $('a[href*=#]').each(function() {
 var thisPath = filterPath(this.pathname) || locationPath;
 if (  locationPath == thisPath
 && (location.hostname == this.hostname || !this.hostname)
 && this.hash.replace(/#/,'') ) {
   var $target = $(this.hash), target = this.hash;
   if (target) {
  var targetOffset = $target.offset().top;
  $(this).click(function(event) {
    event.preventDefault();
    $(scrollElem).animate({scrollTop: targetOffset}, 400, function() {
   // commented line below because it adds a hash to the url and a history item
   // location.hash = target;
    });
  });
   }
 }
  });
  // use the first element that is "scrollable"
  function scrollableElement(els) {
 for (var i = 0, argLength = arguments.length; i <argLength; i++) {
   var el = arguments[i],
    $scrollElement = $(el);
   if ($scrollElement.scrollTop()> 0) {
  return el;
   } else {
  $scrollElement.scrollTop(1);
  var isScrollable = $scrollElement.scrollTop()> 0;
  $scrollElement.scrollTop(0);
  if (isScrollable) {
    return el;
  }
   }
 }
 return [];
  }
});

2 Answers2

6

This happens when the hash target does not exist. In HTML5 a valid hash target can only be written with an id.

So this will not work:

<a name="#hash">Hash</a>

But this will:

<a id="#hash">Hash</a>

Since using name="" isn't valid HTML5, #hash does not exist on the page so when you try to reference it with this:

var $target = $(this.hash) It returns undefined. Even links with valid hash targets won't smooth scroll if they are included after invalid ones because of this.

adotout
  • 1,170
  • 12
  • 17
  • 1
    That makes sense, but even when the hash target exists on the page this is still happening for me. I'm targeting ` –  Jul 30 '13 at 18:55
  • what is that "sizeable chunk of content" ? – Fabi Jul 30 '13 at 19:03
  • Do you have a page that you can reproduce this regularly on? If so, can you open the page in chrome and set a breakpoint on the line where the error occurs "var targetOffset = $target.offset().top;". After you do this, right click on the breakpoint, select "Edit breakpoint", and add "$target.offset() == undefined". The breakpoint should now be orange. If it ever breaks: What is the value of $target? What is the value of "this"? – adotout Jul 30 '13 at 19:15
  • @Fabi, a sizeable chunk is about 1600 characters, out of a page with about 5000 characters (including the characters in the `` etc.) –  Jul 30 '13 at 19:45
  • 1
    By the way, in chrome the error I get is: "Uncaught TypeError: Cannot read property "top" of undefined", in line 17 (`var targetOffset = $target.offset().top;`). –  Jul 30 '13 at 19:49
  • The value (after doing what you said in chrome for a page on which it breaks regularly) for `this` is: `window`, I don't get any other variables on a page on which smooth scrolling isn't working (or I'm doing something wrong). On a page where smooth scrolling *is* working the values are: `$target: x.fn.x.init[1]`, `target: "#header"`, `targetOffset: undefined`, `this: a`, `thisPath: "work"`. Is that what you need, or should there also be a value for $target when smooth scrolling *isn't* working? –  Jul 30 '13 at 20:02
  • what is the difference between one page that is working and one that is not? Just the extra content? – Fabi Jul 30 '13 at 20:15
  • @Fabi: Yes, that is the only change I have to make for smooth scrolling to work again. –  Jul 30 '13 at 20:33
  • I was not able to reproduce the error, only when I did what adotout mentioned - having an anchor that doesnt exist. Since you're looping through all tags, I'd double check for all possible anchors you have on your "non-working" page. – Fabi Jul 30 '13 at 20:46
  • window seems very strange. You said you don't get any variables, try switching to "console" and typing each of the variables. Just typing the variable name + enter should give you the value. – adotout Jul 30 '13 at 22:30
  • @Fabi, @adotout: Ok, tried it again in Chrome. When hovering over $target, it reads `x.fn.x.init[0]` (which I guess is a jquery function), `context: document`, `selector: "#goris"` and `__proto__: Object[0]`. In the "scope variables - local" tab it reads: `target: "#goris"`, `targetOffset: undefined`, `this: a`, `thisPath: "work/article1"`. So it looks like it is selecting the wrong hashlink (#goris is also a hashlink on the page), which is weird, because the link to go back to the top is:`Back to top`. –  Jul 31 '13 at 10:01
  • @Fabi, @adotout: So I found out it is not working because I was using `Hash`, instead of `Hash`, [which isn't valid in HTML5](http://stackoverflow.com/questions/484719/html-anchors-with-name-or-id). Even links that were valid, wouldn't smooth scroll if they were included after invalid ones. The extra content I was removing contained the invalid links, which meant that the valid links were working again. So using `Hash` for all hash anchors fixes it, and smooth scrolling works again! –  Jul 31 '13 at 10:27
  • Your edit got rejected by other people, but I edited the post myself to reflect your proposed changes. – adotout Jul 31 '13 at 11:46
  • @adotout, Thanks! I'll have to award the bounty later (in an hour), can't do it immediately after accepting the answer. Thanks a lot for helping me out! –  Jul 31 '13 at 16:26
0

I know it is an old question, but i had this problem recently and the suggested solution did not help. The used script for smooth scrolling has an error. It only checks if the link links to an anchor. But not if the anchor target actually exists on the current page. So the line

if (target) {

should be

if ($target.length > 0) {
NaN
  • 1