How to Handle Anchor Hash Linking in Angularjs

How to handle anchor hash linking in AngularJS

You're looking for $anchorScroll().

Here's the (crappy) documentation.

And here's the source.

Basically you just inject it and call it in your controller, and it will scroll you to any element with the id found in $location.hash()

app.controller('TestCtrl', function($scope, $location, $anchorScroll) {
$scope.scrollTo = function(id) {
$location.hash(id);
$anchorScroll();
}
});

<a ng-click="scrollTo('foo')">Foo</a>

<div id="foo">Here you are</div>

Here is a plunker to demonstrate

EDIT: to use this with routing

Set up your angular routing as usual, then just add the following code.

app.run(function($rootScope, $location, $anchorScroll, $routeParams) {
//when the route is changed scroll to the proper element.
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
$location.hash($routeParams.scrollTo);
$anchorScroll();
});
});

and your link would look like this:

<a href="#/test?scrollTo=foo">Test/Foo</a>

Here is a Plunker demonstrating scrolling with routing and $anchorScroll

And even simpler:

app.run(function($rootScope, $location, $anchorScroll) {
//when the route is changed scroll to the proper element.
$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
if($location.hash()) $anchorScroll();
});
});

and your link would look like this:

<a href="#/test#foo">Test/Foo</a>

AngularJs with hash in href breaks scrolling and transforms url to hash+fwslash+id

html5Mode

As described in angular add slash before hash in url I tried to turn on the html5 mode by adding:

app.config(function($locationProvider) {
$locationProvider.html5Mode(true);
})

I have set up the base tag in the head section.

These settings made it to start working as expected.

... but I would mention that once the location in the address bar got updated to the referenced hash if I clicked the link again, it just went down a bit and not to the referenced location. Clicking on links with different anchors it works well. Not sure if this is a general bug or only some of my settings are backfiring.

Anchor links in Angularjs?

There are a few ways to do this it seems.

Option 1: Native Angular

Angular provides an $anchorScroll service, but the documentation is severely lacking and I've not been able to get it to work.

Check out http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html for some insight into $anchorScroll.

Option 2: Custom Directive / Native JavaScript

Another way I tested out was creating a custom directive and using el.scrollIntoView().
This works pretty decently by basically doing the following in your directive link function:

var el = document.getElementById(attrs.href);
el.scrollIntoView();

However, it seems a bit overblown to do both of these when the browser natively supports this, right?

Option 3: Angular Override / Native Browser

If you take a look at http://docs.angularjs.org/guide/dev_guide.services.$location and its HTML Link Rewriting section, you'll see that links are not rewritten in the following:

Links that contain target element

Example: <a href="/ext/link?a=b" target="_self">link</a>

So, all you have to do is add the target attribute to your links, like so:

<a href="#anchorLinkID" target="_self">Go to inpage section</a>

Angular defaults to the browser and since its an anchor link and not a different base url, the browser scrolls to the correct location, as desired.

I went with option 3 because its best to rely on native browser functionality here, and saves us time and effort.

Gotta note that after a successful scroll and hash change, Angular does follow up and rewrite the hash to its custom style. However, the browser has already completed its business and you are good to go.

How does AngularJS routing affect simple scroll to top page links?

Yes if you're using conventional anchor tag with href hash linking, then it'll conflict with routing. In angular there's service called $anchorScroll to do that, so your html should be:

<a ng-click="goTo('top')" class="footer__top">Back to top</a>

And in controller of that view have function goTo as:

$scope.goTo = function(id) {
$location.hash(id);
$anchorScroll();
};

Make sure you've injected $location & $anchorScroll as dependencies inside controller.

Plunker

Now above solution is for having hash linking on same page/route. But i you need such in other route then you can handle that centrally on event of $routeChangeSuccess or $stateChangeSuccess or in recent ui-router version Transition.onSuccess as:

$rootScope.$on('$routeChangeSuccess', function(newRoute, oldRoute) {
$location.hash($routeParams.scrollTo);
$anchorScroll();
});

And in some other view have anchor tags like:

<a href="#route1?scrollTo=foo">route1 / Foo</a>
<a href="#route2?scrollTo=bar">route2 / Bar</a>

Plunker

Empty anchor tag value using hash or javascript in Angular

According to the AngularJS docs for the A directive, you should be using href="".

The reasoning for this is to allow easy creation of action links with ngClick directive without changing the location or causing page reloads, e.g.: <a href="" ng-click="model.$save()">Save</a>

How to use native anchor links with angularjs

This topic was further discussed here:

How to handle anchor hash linking in AngularJS

I used a variation from that thread

if $location.$$url[0]== '#'
$location.hash($location.$$url.replace('#', ''))
$anchorScroll()

that basically lets me prefix any anchor links with an additional # and angularjs treats them as traditional anchor



Related Topics



Leave a reply



Submit