ScrollTo function in AngularJS

I am trying to quickly work on navigation. He swims on the side. When they click on the link, she takes them to this identifier on the page. I follow this guide from Treehouse . This is what I have for scrolling:

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

I first placed it in front of </body> . But I seem to encounter a race condition when it shot before quickNav compilation ( ng-hide placed on it, not sure if this causes it, but it is inside the DOM).

If I run this code block in the console, the scroll will work as expected.

I figured it would be more efficient to port this to the controller - or rather, to the directive. But Iโ€™m out of luck. How can I make this code block work with AngularJS?

+60
javascript jquery angularjs scroll anchor
Jun 24 '13 at 19:58
source share
9 answers

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

To help create directives, watch the video at http://egghead.io , starting with the first directive # 10.

to change . To make it scroll to a specific element specified by 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 can use it as follows: <div scroll-on-click></div> to scroll until the element clicks. Or <a scroll-on-click href="#element-id"></div> to scroll to an element with an identifier.

+114
Jun 24 '13 at 21:21
source share

This is the best directive if you want to use it:

You can scroll any element on the page:

 .directive('scrollToItem', function() { return { restrict: 'A', scope: { scrollTo: "@" }, link: function(scope, $elm,attr) { $elm.on('click', function() { $('html,body').animate({scrollTop: $(scope.scrollTo).offset().top }, "slow"); }); } }}) 

Usage (for example, clicking on the "back-to-top" div will scroll until it scrolls up):

 <a id="top-scroll" name="top"></a> <div class="back-to-top" scroll-to-item scroll-to="#top-scroll"> 

It is also supported by chrome, firefox, safari and IE cause the html element, body.

+30
Jul 04 '14 at 15:36
source share

To animate a specific item inside a scroll container (fixed DIV)

 /* @param Container(DIV) that needs to be scrolled, ID or Div of the anchor element that should be scrolled to Scrolls to a specific element in the div container */ this.scrollTo = function(container, anchor) { var element = angular.element(anchor); angular.element(container).animate({scrollTop: element.offset().top}, "slow"); } 
+20
Feb 17 '15 at 9:25
source share

Angular solution using $ anchorScroll http://www.benlesh.com/2013/02/angular-js-scrolling-to-element-by-id.html :

 app.controller('MainCtrl', function($scope, $location, $anchorScroll) { var i = 1; $scope.items = [{ id: 1, name: 'Item 1' }]; $scope.addItem = function (){ i++; //add the item. $scope.items.push({ id: i, name: 'Item ' + i}); //now scroll to it. $location.hash('item' + i); $anchorScroll(); }; }); 

And here is the plunger: http://plnkr.co/edit/xi2r8wP6ZhQpmJrBj1jM?p=preview

And if you care about a pure javascript solution, here is one of them:

Call runScroll in your code with the parent container id and landing page scroll id:

 function runScroll(parentDivId,targetID) { var longdiv; longdiv = document.querySelector("#" + parentDivId); var div3pos = document.getElementById(targetID).offsetTop; scrollTo(longdiv, div3pos, 600); } function scrollTo(element, to, duration) { if (duration < 0) return; var difference = to - element.scrollTop; var perTick = difference / duration * 10; setTimeout(function () { element.scrollTop = element.scrollTop + perTick; if (element.scrollTop == to) return; scrollTo(element, to, duration - 10); }, 10); } 

Link: JavaScript cross-browser (not jQuery ...) scrolls to the top animation

+5
Jun 28 '15 at 18:08
source share

Thanks Andy for the example, it was very helpful. I ended up implementing a slightly different strategy since I am developing one-page scrolling and do not want Angular to be updated when using the hashbang url. I also want to keep the browser back / forward action.

Instead of using directive and hash, I use $ scope. $ watch on $ location.search and get the target from there. This gives a nice clean anchor tag.

<a ng-href="#/?scroll=myElement">My element</a>

I chained the clock code to the declaration of my module in app.js as follows:

 .run(function($location, $rootScope) { $rootScope.$watch(function() { return $location.search() }, function(search) { var scrollPos = 0; if (search.hasOwnProperty('scroll')) { var $target = $('#' + search.scroll); scrollPos = $target.offset().top; } $("body,html").animate({scrollTop: scrollPos}, "slow"); }); }) 

The caveat with the code above is that if you access the URL directly from another route, the DOM cannot be loaded in time to call jQuery $ target.offset (). The solution is to embed this code in the $ viewContentLoaded observer. The final code looks something like this:

 .run(function($location, $rootScope) { $rootScope.$on('$viewContentLoaded', function() { $rootScope.$watch(function() { return $location.search() }, function(search) { var scrollPos = 0 if (search.hasOwnProperty('scroll')) { var $target = $('#' + search.scroll); var scrollPos = $target.offset().top; } $("body,html").animate({scrollTop: scrollPos}, "slow"); }); }); }) 

Tested with Chrome and FF

+4
Sep 02 '13 at 19:27
source share

I used andrew joslin answer, which works great, but caused an angular route change that created an awesome scroll for me. If you want to avoid changing the route,

 myApp.directive('scrollOnClick', function() { return { restrict: 'A', link: function(scope, $elm, attrs) { var idToScroll = attrs.href; $elm.on('click', function(event) { event.preventDefault(); var $target; if (idToScroll) { $target = $(idToScroll); } else { $target = $elm; } $("body").animate({scrollTop: $target.offset().top}, "slow"); return false; }); } } }); 
+4
Jul 26 '15 at 6:57
source share

What about angular-scroll , it is actively supported and there is no jQuery dependency ..

+1
May 19 '15 at 8:31
source share

Another suggestion. One directive with a selector.

HTML:

 <button type="button" scroll-to="#catalogSection">Scroll To</button> 

Angular:

 app.directive('scrollTo', function () { return { restrict: 'A', link: function (scope, element, attrs) { element.on('click', function () { var target = $(attrs.scrollTo); if (target.length > 0) { $('html, body').animate({ scrollTop: target.offset().top }); } }); } } }); 

Also pay attention to $ anchorScroll

+1
Sep 07 '16 at 6:47
source share

Resuming this old thread to add a fix for some who may not have been able to use any of the directives listed here. Both bodies and html should not have a set percentage height, otherwise the effect is not observed. An automatic value can fix the problem without limiting page size.

 body, html { height: auto; } 
0
Jul 02 '17 at 14:38
source share



All Articles