Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I prevent the browser from jumping to an anchor when the URL's fragment identifier is changed to it? [duplicate]

We've got a few pages using ajax to load in content and there's a few occasions where we need to deep link into a page. Instead of having a link to "Users" and telling people to click "settings" it's helpful to be able to link people to user.aspx#settings

To allow people to provide us with correct links to sections (for tech support, etc.) I've got it set up to automatically modify the hash in the URL whenever a button is clicked. The only issue of course is that when this happens, it also scrolls the page to this element.

Is there a way to disable this? Below is how I'm doing this so far.

$(function(){
    //This emulates a click on the correct button on page load
    if(document.location.hash){
     $("#buttons li a").removeClass('selected');
     s=$(document.location.hash).addClass('selected').attr("href").replace("javascript:","");
     eval(s);
    }

    //Click a button to change the hash
    $("#buttons li a").click(function(){
            $("#buttons li a").removeClass('selected');
            $(this).addClass('selected');
            document.location.hash=$(this).attr("id")
            //return false;
    });
});

I had hoped the return false; would stop the page from scrolling - but it just makes the link not work at all. So that's just commented out for now so I can navigate.

Any ideas?

like image 839
FiniteLooper Avatar asked Nov 25 '22 16:11

FiniteLooper


2 Answers

Use history.replaceState or history.pushState* to change the hash. This will not trigger the jump to the associated element.

Example

$(document).on('click', 'a[href^=#]', function(event) {
  event.preventDefault();
  history.pushState({}, '', this.href);
});

Demo on JSFiddle

* If you want history forward and backward support

History behaviour

If you are using history.pushState and you don't want page scrolling when the user uses the history buttons of the browser (forward/backward) check out the experimental scrollRestoration setting (Chrome 46+ only).

history.scrollRestoration = 'manual';
  • spec
  • info

Browser Support

  • replaceState
  • pushState
  • polyfill
like image 65
HaNdTriX Avatar answered Nov 28 '22 06:11

HaNdTriX


Step 1: You need to defuse the node ID, until the hash has been set. This is done by removing the ID off the node while the hash is being set, and then adding it back on.

hash = hash.replace( /^#/, '' );
var node = $( '#' + hash );
if ( node.length ) {
  node.attr( 'id', '' );
}
document.location.hash = hash;
if ( node.length ) {
  node.attr( 'id', hash );
}

Step 2: Some browsers will trigger the scroll based on where the ID'd node was last seen so you need to help them a little. You need to add an extra div to the top of the viewport, set its ID to the hash, and then roll everything back:

hash = hash.replace( /^#/, '' );
var fx, node = $( '#' + hash );
if ( node.length ) {
  node.attr( 'id', '' );
  fx = $( '<div></div>' )
          .css({
              position:'absolute',
              visibility:'hidden',
              top: $(document).scrollTop() + 'px'
          })
          .attr( 'id', hash )
          .appendTo( document.body );
}
document.location.hash = hash;
if ( node.length ) {
  fx.remove();
  node.attr( 'id', hash );
}

Step 3: Wrap it in a plugin and use that instead of writing to location.hash...

like image 35
Borgar Avatar answered Nov 28 '22 04:11

Borgar