Search code examples
javascriptjqueryangularjsscrollanchor

ScrollTo function in AngularJS


I'm trying to get a quick nav to work correctly. It's floating on the side. When they click on a link, it takes them to that ID on the page. I'm following this guide from Treehouse. This is what I have for the scrolling:

$("#quickNav a").click(function(){
    var quickNavId = $(this).attr("href");
    $("html, body").animate({scrollTop: $(location).offset().top}, "slow");
    return false;
});

I initially placed it before the </body>. But I seem to be running into a race condition where that was firing before the quickNav compiled (it has a ng-hide placed on it, not sure if that's causing it - but it is within the DOM).

If I run that block of code in the console, then the scrolling works as expected.

I figured it'd be more effective to move this into the controller - or more likely within a directive. But I'm not having luck accomplishing that. How can I get this block of code to work with AngularJS?


Solution

  • Here is a simple directive that will scroll to an element on click:

    myApp.directive('scrollOnClick', function() {
      return {
        restrict: 'A',
        link: function(scope, $elm) {
          $elm.on('click', function() {
            $("body").animate({scrollTop: $elm.offset().top}, "slow");
          });
        }
      }
    });
    

    Demo: http://plnkr.co/edit/yz1EHB8ad3C59N6PzdCD?p=preview

    For help creating directives, check out the videos at http://egghead.io, starting at #10 "first directive".

    edit: To make it scroll to a specific element specified by a href, just check attrs.href.

    myApp.directive('scrollOnClick', function() {
      return {
        restrict: 'A',
        link: function(scope, $elm, attrs) {
          var idToScroll = attrs.href;
          $elm.on('click', function() {
            var $target;
            if (idToScroll) {
              $target = $(idToScroll);
            } else {
              $target = $elm;
            }
            $("body").animate({scrollTop: $target.offset().top}, "slow");
          });
        }
      }
    });
    

    Then you could use it like this: <div scroll-on-click></div> to scroll to the element clicked. Or <a scroll-on-click href="#element-id"></div> to scroll to element with the id.