30

I have various links which all have unique id's that are "pseudo-anchors." I want them to affect the url hash value and the click magic is all handled by some mootools code. However, when I click on the links they scroll to themselves (or to the top in one case). I don't want to scroll anywhere, but also need my javascript to execute and to have the hash value in the url update.

Simulated sample code:

<a href="#button1" id="button1">button 1</a>
<a href="#button2" id="button2">button 2</a>
<a href="#" id="reset">Home</a>

So if you were to click on the "button 1" link, the url could be http://example.com/foo.php#button1

Does anyone have any ideas for this? Simply having some javascript return void kills the scrolling but also kills my javascript (though I could probably work around that with an onclick) but more importantly, prevents the hash value in the url to change.

Neil
  • 1,813
  • 1
  • 12
  • 20
  • Why do you want the anchor to appear in the URL? – hobodave Aug 02 '09 at 02:47
  • Probably working with the hash values like Twitter that will update the page in some way. – random Aug 02 '09 at 02:49
  • 1
    The anchors are acting as a way to maintain back and forward button support. I guess using "tab1" instead of "button1" in the sample snippet would make that more apparent. – Neil Aug 02 '09 at 02:55
  • There’s a couple of clever ideas here: http://stackoverflow.com/questions/1489624/modifying-document-location-hash-without-page-scrolling – Paul D. Waite Feb 13 '10 at 13:15

9 Answers9

37

The whole point of an anchor link is to scroll a page to a particular point. So if you don't want that to happen, you need to attach an onclick handler and return false. Even just adding it as an attribute should work:

<a href="#button1" id="button1" onclick="return false">button 1</a>

A side of effect of the above is that the URL itself won't change, since returning false will cancel the event. So since you want the URL to actually change, you can set the window.location.hash variable to the value that you want (that is the only property of the URL that you can change without the browser forcing a reload). You can probably attach an event handler and call something like window.location.hash = this.id though I'm not sure how mootools handles events.

(Also you need all of the IDs to be unique)

Adam Batkin
  • 51,711
  • 9
  • 123
  • 115
  • Ya, I can set window.location.hash to "#" manually, but *that* forces the browser to jump to the top. – Neil Aug 02 '09 at 03:03
25

You can use the code below to avoid scrolling:

<a href="javascript:void(0);">linktxt</a>
kip
  • 251
  • 3
  • 2
9

I'm probably missing something, but why not just give them different IDs?

<a href="#button1" id="button-1">button 1</a>
<a href="#button2" id="button-2">button 2</a>
<a href="#" id="reset">Home</a>

Or whatever convention you'd prefer.

Peter Bailey
  • 105,256
  • 31
  • 182
  • 206
  • 3
    Browser will still shift because the URL has "changed" to the new location. – random Aug 02 '09 at 02:48
  • 1
    Thanks a lot for suggesting to make the id's unique (I simply tacked on a hyphen on the id's and then perform some basic concatenation in my code to account for that). Works perfectly the way I want (at least in Firefox and Safari, haven't tested in IE yet though I suspect it should be fine.) However, one lingering issue is with the Home link whose anchor is basically nothing ("#"). That still scrolls to the top, and if I have an onclick="return false" (as Adam Batkin suggested) the url hash value doesn't change. I could just make it href="#home" or something but I really wouldn't. Ideas? – Neil Aug 02 '09 at 03:00
  • Still not seeing why it needs to be #foo -- is there a programmatic reason for that arrangement? URLs already have other means for representing data in the URL, no javascript trickery required. – anschauung Aug 02 '09 at 03:17
  • Well, if the url was bar.html#tab1 then you navigated to bar.html#tab2 it makes it easier to no when you go hit the back button what page you're on. But let's say the "home" button is like a "hide-all-tabs" button. The only reason why I want the anchors is to make the urls bookmark-able/sendable and it doesn't cause the page to reload. When that page is reopened, I already know which "tab" was bookmarked so I can just go back to that. I hate to plug my own site, but if you click on the icons, home button, then try and use the browser back button you'll see. http://www.shinyfoil.com/ – Neil Aug 02 '09 at 03:32
  • I see what you mean now -- thanks for the example (and nice site, btw). But, since you're trying to circumvent some of the basic rules of how the web is supposed to work -- anchors just aren't meant to work like that -- I suppose you'll need trickery after all. Suggested trick: having all the "real" anchors (#matches, etc) inside a hidden div, set about 200 pixels down and fixed using CSS position: fixed. – anschauung Aug 02 '09 at 04:27
5

Also, preventDefault

    $(your-selector).click(function (event) {
        event.preventDefault();
        //rest of your code here
    }
Vinay Raghu
  • 1,269
  • 2
  • 13
  • 22
3

I found the solution. Here I save an old location from calling href and restore it after scrolling

<script language="JavaScript" type="text/javascript">
<!--
function keepLocation(oldOffset) {
  if (window.pageYOffset!= null){
    st=oldOffset;
  }
  if (document.body.scrollWidth!= null){
    st=oldOffset;
  }
  setTimeout('window.scrollTo(0,st)',10);
}
//-->
</script>

and in body of page

<a href="#tab1" onclick="keepLocation(window.pageYOffset);" >Item</a> 

Thanks to sitepoint

Jeff_Alieffson
  • 2,672
  • 29
  • 34
1

An easier way would probably be to add it as a GET. That is, http://example.com/foo.php?q=#button1 instead of http://example.com/foo.php#button1

This won't have any effect on how the page is displayed (unless you want it to), and most scripting languages already have tools in place to easily (and safely) read the data.

anschauung
  • 3,697
  • 3
  • 24
  • 34
1

Well here we are 7 years after this answer was published and I found a different way to make it work: just point the window.location.hash to a non-existent anchor! It doesn't work for <a>s but works perfectly in <div>s.

<div onclick="window.location.hash = '#NonExistentAnchor';">button 1</div>

Worked fine in Chrome 56, Firefox 52 and Edge (IE?) 38. Another good point is that this doesn't produce any console errors or warnings.

Hope it helps somebody besides me.

Heitor
  • 683
  • 2
  • 12
  • 26
0

There is a solution without any JavaScript at all:

<a href="#!">I will not jump to the top</a>
sandreas
  • 101
  • 1
  • 7
0

Use

<a href="#button1" id="button1" onclick="setHash(this.id)">button 1</a>

where

function setHash(hash) {
            event.preventDefault();        
            history.pushState(null, null, "#"+hash);
}

event.preventDefault() stops browser from what it normally would do on clicking, and history.pushState adds to the sessions history stack.

For further discussion, see here and here