79

Is it possible to use anchor links with Angularjs?

I.e.:

 <a href="#top">Top</a>
 <a href="#middle">Middle</a>
 <a href="#bottom">Bottom</a>

 <div name="top"></div>
 ...
 <div name="middle"></div>
 ...
 <div name="bottom"></div>

Thank you

Andriy Drozdyuk
  • 58,435
  • 50
  • 171
  • 272

11 Answers11

108

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.

Courcelan
  • 1,096
  • 2
  • 8
  • 3
  • 1
    Unfortunately there are lots of leftover side effects from the extra hash in the address bar. I found option 2 here much more effective. Someone already wrote the directive, to boot: http://ngmodules.org/modules/ngScrollTo – Riley Lark Nov 27 '13 at 02:04
  • Option 2 here is definitely the simplest, especially if you are using routing. I had a problem with layered tabs using Bootstrap, and Opt2 made it stupid simple. Thank you – Dameo Oct 18 '14 at 20:15
  • reached your answer twice by now.. helped me twice.. if I could upvote again, I would. the target="_self" is the best solution for me. – guy mograbi Sep 10 '15 at 17:54
  • 4
    There is one problem with setting target="_self". If I give someone something like this link http://stackoverflow.com/#footer , it will not navigate to footer. It only navigate to footer if you click on Go to Footer. Any ideal? This is important since I usually give my friend a link like that to show which part he/she need to focus on. – Ryan May 17 '16 at 14:57
  • 3
    Unfortunately option 3 will redirect me to the root of the website .i.e. http://localhost:9000/#medical instead of http://localhost:9000/#/case/1#medical. even with the _self target. – Rafael Jun 02 '16 at 08:23
  • 1
    Option 3 worked fantastically for a "skip to content" link! Thank you! – Lane Sawyer Sep 22 '17 at 17:58
  • For the second option, Instead of scrolling to the item as described here, I would suggest setting the focus to the item (should be able to be be done with a simple dom query for the ID). That will allow the browser to scroll to it natively, and be more accessibility friendly since keyboard users would be redirected as well. – brandonbradley Jul 09 '20 at 18:08
27

I don't know if that answers your question, but yes, you can use angularjs links, such as:

<a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>

There is a good example on the AngularJS website:

http://docs.angularjs.org/api/ng.directive:ngHref

UPDATE: The AngularJS documentation was a bit obscure and it didn't provide a good solution for it. Sorry!

You can find a better solution here: How to handle anchor hash linking in AngularJS

Community
  • 1
  • 1
Paola Cerioli
  • 741
  • 7
  • 7
25

You could try to use anchorScroll.

Example

So the controller would be:

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

And the view:

<a href="" ng-click="scrollTo('foo')">Scroll to #foo</a>

...and no secret for the anchor id:

<div id="foo">
  This is #foo
</div>
Edmar Miyake
  • 12,047
  • 3
  • 37
  • 38
  • 2
    Note: the `$anchorScroll()` call following the `$location.hash()` call is unnecessary, as `$anchorScroll` watches `$location.hash` automatically(). – PLPeeters Dec 16 '15 at 10:43
  • The docs call [$anchorScroll()](https://docs.angularjs.org/api/ng/service/$anchorScroll#!) in their example, but @Edmar you are right, omitting `$anchorScroll()` still scrolls to the new location. – twknab Aug 25 '17 at 03:10
8

$anchorScroll is indeed the answer to this, but there's a much better way to use it in more recent versions of Angular.

Now, $anchorScroll accepts the hash as an optional argument, so you don't have to change $location.hash at all. (documentation)

This is the best solution because it doesn't affect the route at all. I couldn't get any of the other solutions to work because I'm using ngRoute and the route would reload as soon as I set $location.hash(id), before $anchorScroll could do its magic.

Here is how to use it... first, in the directive or controller:

$scope.scrollTo = function (id) {
  $anchorScroll(id);  
}

and then in the view:

<a href="" ng-click="scrollTo(id)">Text</a>

Also, if you need to account for a fixed navbar (or other UI), you can set the offset for $anchorScroll like this (in the main module's run function):

  .run(function ($anchorScroll) {
      //this will make anchorScroll scroll to the div minus 50px
      $anchorScroll.yOffset = 50;
  });
Rebecca
  • 1,064
  • 13
  • 12
1

I had the same problem, but this worked for me:

<a ng-href="javascript:void(0);#tagId"></a>
yvesmancera
  • 2,915
  • 5
  • 24
  • 33
1

Works for me:

 <a onclick='return false;' href="" class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" ng-href="#profile#collapse{{$index}}"> blalba </a>
Imran Omar Bukhsh
  • 7,849
  • 12
  • 59
  • 81
1

You need to only add target="_self" to your link

ex. <a href="#services" target="_self">Services</a><div id="services"></div>

Farzad.Kamali
  • 553
  • 4
  • 10
0

Or you could simply write:

ng-href="\#yourAnchorId"

Please notice the backslash in front of the hash symbol

Marko
  • 9
  • 1
0

The best choice to me was to create a directive to do the work, because $location.hash() and $anchorScroll() hijack the URL creating lots of problems to my SPA routing.

MyModule.directive('myAnchor', function() {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function(scope, elem, attrs, ngModel) {
      return elem.bind('click', function() {
        //other stuff ...
        var el;
        el = document.getElementById(attrs['myAnchor']);
        return el.scrollIntoView();
      });      
    }
  };
});
T J
  • 42,762
  • 13
  • 83
  • 138
0

If you are using SharePoint and angular then do it like below:

<a ng-href="{{item.LinkTo.Url}}" target="_blank" ng-bind="item.Title;" ></a> 

where LinkTo and Title is SharePoint Column.

Amay Kulkarni
  • 828
  • 13
  • 16
0

You can also Navigate to HTML id from inside controller

$location.hash('id_in_html');
vijay
  • 10,276
  • 11
  • 64
  • 79