0

Until now I have always been using jQuery for my single page "scroll to div" applications, but since in making an Angular app (just for learning purposes) I try to do everything in angular instead of falling back on good ol' jQuery.

Im trying to make a scroll-to-div-on-the-same-page-menu, but Im not really sure on how to do this in Angular tho.

Currently I'm using this snippet to do what I want:

JS

app.directive('scrollOnClick', function() {
      return {
        restrict: 'A',
        link: function(scope, $elm, attrs) {
          $elm.click(function() {
            var linkHref = attrs.href;
            angular.element('html,body').animate({
              // select the element the href points to
              scrollTop: angular.element(linkHref).offset().top - 60
            }, 'slow');
          });
        }
      }
    });

HTML

<div class="navbar navbar-default navbar-fixed-top" role="navigation">
  <div class="container">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a ng-href="/" role="button" class="navbar-brand">angularApp</a>
    </div>
    <div class="navbar-collapse collapse">
      <ul class="nav navbar-nav">
        <li><a href="##one">One</a></li>
        <li><a href="##two">Two</a></li>
        <li><a href="##three">Three</a></li>
      </ul>
    </div>
  </div>
</div>
<div id="page-wrap">
  <div id="one">...</div>
  <div id="two">...</div>
  <div id="three">...</div>
</div>

But it doesn't work perfectly.

I need it to scroll with a margin of 60px as you can se in the code, because of my fixed navbar. I also want it to navigate slower and have a pretty url like /two instead of /#two. How is this achieved?

  • Is this of any help: http://stackoverflow.com/questions/17284005/scrollto-function-in-angularjs – james May 02 '14 at 17:52
  • I think it is, but I can't make sense of it to translate what jQuery is doing for me. Its almost the same code as I suggested the angular code to might be. The problem is that the code doesn't do the same as the jQuery snippet does. –  May 02 '14 at 17:55

2 Answers2

0

If you have jQuery loaded already, you can use angular.element as an alias for $. That's usually the "proper" way to do it in angular. If you don't load jQuery first, angular.element uses jQLite, which is limited in terms of what selectors are available. Since you're already using jQuery, lets assume you already have it loaded up before angular.

Assuming that your jQuery example is working the way you like, you can just use the same selectors, substituting $elm for target, subtract the 60px and also set the animation timer to 1000 as you did in your jQuery example.

Try something like this:

app.directive('scrollOnClick', function() {
  return {
    restrict: 'A',
    link: function(scope, $elm) {
      $elm.click(function() {
        // same as your jQuery example
        angular.element('html,body').animate({
          scrollTop: $elm.offset().top - 60
        }, 1000);
      });
    }
  }
});

--EDIT--

Wait, I see what you're trying to do here...

You need to get the href attribute from your element. The link function can take a third argument, which is the attributes attached to the element. Then instead of setting scrollTop to the offset of the link you clicked, you set it to the offset of the element in the href, using angular.element to select that. Like this:

app.directive('scrollOnClick', function() {
  return {
    restrict: 'A',
    link: function(scope, $elm, attrs) {
      $elm.click(function() {
        var linkHref = attrs.href;
        angular.element('html,body').animate({
          // select the element the href points to
          scrollTop: angular.element(linkHref).offset().top - 60
        }, 1000);
      });
    }
  }
});
jshanley
  • 9,048
  • 2
  • 37
  • 44
  • Thank you! I dont have time right now but I will look at it later! Looks good though. :) –  May 04 '14 at 09:38
  • Okay then. Finally figured it out...Almost... I tried the last directive you made but what I did was I took away `linkHref` and replaced it with `'#'`. But then the links had to have two hastags instead of just one like: `Two` . When I did that it worked, but there were no animation or 60px offset. –  May 06 '14 at 12:43
  • Replaced `#` back to `linkHref` as it seems to be working when I added `var app = angular.module('AngularAppApp', []);`. Still cant make it work with animation and without the double hastags in href. Do I need to use `ng-href`? Tried but still doesn't work. –  May 06 '14 at 18:07
0

I ended up using angular-scrollto which I think is very good. Very simple to use. All I had to do after I installed it with bower was to inject the module and the simply add this to my HTML (just an example from the github):

<a href="" scroll-to="#element" offset="0" container="html, body">Go to element</a>

<div id="element">
  You will scroll to me
</div>