Reading the AngularJS docs I haven\'t figured out if $anchorScroll
can have a duration/easing option to smooth scroll to elements.
It only says:
None of the solutions here actually does what OP originally asked, that is, make $anchorScroll
scrolling smoothly.
Difference between smooth scrolling directives and $anchroScroll
is that it uses/modifies $location.hash()
, which may be desirable in some cases.
Here is gist for simple module that replaces $anchorScroll scrolling with smooth scrolling. It uses https://github.com/oblador/angular-scroll library for the scrolling itself (replace it with something else if you want, it should be easy).
https://gist.github.com/mdvorak/fc8b531d3e082f3fdaa9
Note: It actually does not get $anchorScroll to scroll smoothly, but it replaces its handler for scrolling.
Enable it simply by referencing mdvorakSmoothScroll
module in your application.
I am not aware of how to animate $anchorScroll
. Here's how I do it in my projects:
/* Scroll to top on each ui-router state change */
$rootScope.$on('$stateChangeStart', function() {
scrollToTop();
});
And the JS function:
function scrollToTop() {
if (typeof jQuery == 'undefined') {
return window.scrollTo(0,0);
} else {
var body = $('html, body');
body.animate({scrollTop:0}, '600', 'swing');
}
log("scrollToTop");
return true;
}
Alan, thank you. If anyone interested, I formatted it based on John Pappa standards.
(function() {
'use strict';
var moduleId = 'common';
var serviceId = 'anchorSmoothScroll';
angular
.module(moduleId)
.service(serviceId, anchorSmoothScroll);
anchorSmoothScroll.$inject = ['$document', '$window'];
function anchorSmoothScroll($document, $window) {
var document = $document[0];
var window = $window;
var service = {
scrollDown: scrollDown,
scrollUp: scrollUp,
scrollTo: scrollTo,
scrollToTop: scrollToTop
};
return service;
function getCurrentPagePosition(currentWindow, doc) {
// Firefox, Chrome, Opera, Safari
if (currentWindow.pageYOffset) return currentWindow.pageYOffset;
// Internet Explorer 6 - standards mode
if (doc.documentElement && doc.documentElement.scrollTop)
return doc.documentElement.scrollTop;
// Internet Explorer 6, 7 and 8
if (doc.body.scrollTop) return doc.body.scrollTop;
return 0;
}
function getElementY(doc, element) {
var y = element.offsetTop;
var node = element;
while (node.offsetParent && node.offsetParent !== doc.body) {
node = node.offsetParent;
y += node.offsetTop;
}
return y;
}
function scrollDown(startY, stopY, speed, distance) {
var timer = 0;
var step = Math.round(distance / 25);
var leapY = startY + step;
for (var i = startY; i < stopY; i += step) {
setTimeout('window.scrollTo(0, ' + leapY + ')', timer * speed);
leapY += step;
if (leapY > stopY) leapY = stopY;
timer++;
}
};
function scrollUp(startY, stopY, speed, distance) {
var timer = 0;
var step = Math.round(distance / 25);
var leapY = startY - step;
for (var i = startY; i > stopY; i -= step) {
setTimeout('window.scrollTo(0, ' + leapY + ')', timer * speed);
leapY -= step;
if (leapY < stopY) leapY = stopY;
timer++;
}
};
function scrollToTop(stopY) {
scrollTo(0, stopY);
};
function scrollTo(elementId, speed) {
var element = document.getElementById(elementId);
if (element) {
var startY = getCurrentPagePosition(window, document);
var stopY = getElementY(document, element);
var distance = stopY > startY ? stopY - startY : startY - stopY;
if (distance < 100) {
this.scrollToTop(stopY);
} else {
var defaultSpeed = Math.round(distance / 100);
speed = speed || (defaultSpeed > 20 ? 20 : defaultSpeed);
if (stopY > startY) {
this.scrollDown(startY, stopY, speed, distance);
} else {
this.scrollUp(startY, stopY, speed, distance);
}
}
}
};
};
})();
You can also use the angular-scroll, link "https://github.com/durated/angular-scroll/". It is smooth scrolling also few easing functions to get a professional look.
Unfortunately this is not possible using $anchorScroll
. As you discovered $anchorScroll
doesn't have any options and doesn't work with $ngAnimate
. In order to animate the scroll you would need to use your own service/factory or just straight javascript.
For the sake of self-learning I put together an example with a smooth scrolling service. There are probably better ways to do this so any feedback is encouraged.
To scroll to an element you attach a ng-click="gotoElement(ID)"
to any element. I think an even better route would be to make this a directive.
Here's the working example on jsFiddle.
Update
There are now a number of third-party directives for accomplishing this.
You can also use ngSmoothScroll, link: https://github.com/d-oliveros/ngSmoothScroll.
Just include the smoothScroll
module as a dependency and use it like this:
<a href="#" scroll-to="my-element-3">Click me!</a>