Search code examples
javascriptjqueryhtmlanchorhashbang

Html anchor linking and hashbang, simple solution?


I have in http://www.g3eo.com/#!/page_About the following in line 96:

<li><a href="#!/page_Services">Side scan sonar surveys</a></li>

and need to create an anchor to go to line 180:

<li id="sidescan"><strong>Side scan sonar surveys</strong></li>

I understand that to get this working I would need to do:

<li><a href="#!/page_Services#sss">Side scan sonar surveys</a></li>
<li id="sidescan"><a name="sss"><strong>Side scan sonar surveys</strong></a></li>

But this does nothing. I was wondering if the problem is the hashbang in #!/page_Services, without it the web page stops working properly.


Solution

  • I started working on a solution very similar to @Liam Egan's, which is good, but I thought "What if someone wants to share a link to an anchor tag? I'll just try using both a hashbang and an anchor hash in the URL!".

    After multiple tests, as it turns out, it's really hard to maintain, especially if you use an external library which uses the hash. It will break, so I abandoned that idea.

    Here is a solution for clicks on links, which I tested on your website:

    $(function(){
        $('a[href^="#"]').click(function(e){
            // Get the hashes in link
            var h = this.href.split('#');
            // If the first hash is not a hashbang or if there are several hashes
            if(h[1].indexOf('!') !== 0 || h.length > 2) {
                // Prevent default behavior of the link so it does not break the site
                e.preventDefault();
                // If the first hash is a hashbang (but there are multiple hashes),
                // only include the first one in the page URL
                if(h[1].indexOf('!') === 0) { window.location.hash = '#' + h[1]; }
                // Get the element with the right ID (last hash) and its scrolling container
                var el = $('#' + h.pop()), cont = el.closest('div[class^="scroll"]');
                // Scroll the scrolling container to that element after a delay,
                // because it does not work during the page transition
                setTimeout(function() {
                    cont.scrollTop(0) // Reset it first to get the right position below
                        .scrollTop( el.position().top );
                },500);
            }
        });
    });
    

    I had to adapt it for two reasons:

    • Not the whole document should scroll, just your wrapping .scroll div
    • The scrolling won't work during page transition, so it needs a delay

    It does not affect links such as #!/page_XXX, and will work with links such as #myID or #!/page_XXX#myID.

    Finally, for simplicity, since you are using jQuery, I did too. Place that piece of code anywhere on your page after loading jQuery, and it should work.