I am having trouble getting a smooth scroll service to work in angular 2. Are there any services for smooth scrolling, or plain anchor scrolling, that might work until the angular 2 team gets the $anchorScroll angular2 equivalent working?
So far I have just tried:
Setting *ngFor loop incremental id on a parent div
[attr.id]="'point' + i"
Calling a scrollto on a button with the id passed
<button
type="button"
class="btn btn-lg btn-default "
(click)="smoothScroll('point'+i)">
Scroll to point
</button>
And in the associated component I am trying to implement a plain js smooth scroll function
smoothScroll(eID) {
var startY = currentYPosition();
var stopY = elmYPosition(eID);
var distance = stopY > startY ? stopY - startY : startY - stopY;
if (distance < 100) {
scrollTo(0, stopY); return;
}
var speed = Math.round(distance / 100);
if (speed >= 20) speed = 20;
var step = Math.round(distance / 25);
var leapY = stopY > startY ? startY + step : startY - step;
var timer = 0;
if (stopY > startY) {
for (var i = startY; i < stopY; i += step) {
setTimeout(this.win.scrollTo(0, leapY), timer * speed);
leapY += step; if (leapY > stopY) leapY = stopY; timer++;
} return;
}
for (var i = startY; i > stopY; i -= step) {
setTimeout(this.win.scrollTo(0,leapY), timer * speed);
leapY -= step; if (leapY < stopY) leapY = stopY; timer++;
}
}
function currentYPosition() {
// Firefox, Chrome, Opera, Safari
if (self.pageYOffset) return self.pageYOffset;
// Internet Explorer 6 - standards mode
if (document.documentElement && document.documentElement.scrollTop)
return document.documentElement.scrollTop;
// Internet Explorer 6, 7 and 8
if (document.body.scrollTop) return document.body.scrollTop;
return 0;
}
function elmYPosition(eID) {
var elm = document.getElementById(eID);
var y = elm.offsetTop;
var node = elm;
while (node.offsetParent && node.offsetParent != document.body) {
node = node.offsetParent;
y += node.offsetTop;
} return y;
}
I'm also trying to give access to the window for the this._win.scrollTo which is coming from a window provider service
import {Injectable, Provider} from 'angular2/core';
import {window} from 'angular2/src/facade/browser';
import {unimplemented} from 'angular2/src/facade/exceptions';
function _window(): Window {
return window
}
export abstract class WINDOW {
get nativeWindow(): Window {
return unimplemented();
}
}
class WindowRef_ extends WINDOW {
constructor() {
super();
}
get nativeWindow(): Window {
return _window();
}
}
export const WINDOW_PROVIDERS = [
new Provider(WINDOW, { useClass: WindowRef_ }),
];
** EDIT ---------------------**
I changed the this.win.scrollTo to this.win.window.scrollTo and now I am getting an effect similar to angular1.x $anchorscroll where the scroll is a snappy just instead of a smooth transition, but the scroll is not smooth and I am getting the following exception error.
UPDATE
I am no longer getting that error after finding out that angular2 is doing the setTimeout a bit differently, but the scroll is still instantaneous and not a smooth scroll.
I changed
setTimeout(this.win.scrollTo(0, leapY), timer * speed);
to
setTimeout(() => this.win.scrollTo(0, leapY), timer * speed);
There is another approach, which sould be considered: using jQuery.
Maybe it is not so elegant as the native solutions, but very easy and works perfectly.
In your index.html you have to add this to the end of the body:
And now you can use the simple
<a href("#section")>
navigation like this:It also works with routing:
For anyone still on the search for a smooth scroll @alex-j 's answer works great for me in Angular 2.0 - but I had to change the Window service to this :-
All props to this blog http://juristr.com/blog/2016/09/ng2-get-window-ref/ - now I have a smooth scroll service I can call from anywhere :)
The easier way to achieve this is by using this polyfill: http://iamdustan.com/smoothscroll/
Now you can use behavior option of scrollIntoView as:
(document.querySelector('#'+ anchor)).scrollIntoView({ behavior: 'smooth' });
If you want a very simple anchor jump that works after routing and within routed views, you can also use ng2-simple-page-scroll.
Or right after routing:
It does a simple instant jump, but it works.
Alright, after scratching my head a little bit, here is a solution that seems to be working ok.
Same as before, I declared my conditional id and a button with the scrollTo function call when clicked.
Now, there are only two files in the solution is a service that will help return the document window and the template's component. Nothing was changed in the window service from the state above but I will include it again for the sake of a good answer.
window.service.ts : shout out to https://gist.github.com/lokanx/cc022ee0b8999cd3b7f5 for helping with this piece
app.component.ts
I created a plunk to show this example working: Plunk Example
i use this code .