Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smooth scroll angular2

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.

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); 
like image 938
Alex J Avatar asked Mar 18 '16 18:03

Alex J


2 Answers

there is a method in the window object called scrollTo(). If you set the behavior to 'smooth' the page will handle the smooth scroll. example (scroll to top of page):

 window.scrollTo({ left: 0, top: 0, behavior: 'smooth' }); 

And with fallback example:

    try      {       window.scrollTo({ left: 0, top: 0, behavior: 'smooth' });      } catch (e) {       window.scrollTo(0, 0);       } 
like image 168
Mert Avatar answered Sep 20 '22 02:09

Mert


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

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_ }), ]; 

app.component.ts

import { bootstrap } from 'angular2/platform/browser'; import { Component } from 'angular2/core'; import {WINDOW, WINDOW_PROVIDERS} from './window.service';  @Component({   selector: 'my-app',   templateUrl: 'app.tpl.html',   providers: [WINDOW_PROVIDERS] })  class AppComponent {     win: Window;     private offSet: number;     constructor(         private _win: WINDOW) {          this.win = _win.nativeWindow;     }     title = 'Ultra Racing';     things = new Array(200);      scrollTo(yPoint: number, duration: number) {         setTimeout(() => {             this.win.window.scrollTo(0, yPoint)         }, duration);         return;     }     smoothScroll(eID) {         var startY = currentYPosition();         var stopY = elmYPosition(eID);         var distance = stopY > startY ? stopY - startY : startY - stopY;         if (distance < 100) {             this.win.window.scrollTo(0, stopY); return;         }         var speed = Math.round(distance / 100);         if (speed >= 20) speed = 20;         var step = Math.round(distance / 100);         var leapY = stopY > startY ? startY + step : startY - step;         var timer = 0;         if (stopY > startY) {             for (var i = startY; i < stopY; i += step) {                 this.scrollTo(leapY, timer * speed);                 leapY += step; if (leapY > stopY) leapY = stopY; timer++;             } return;         }         for (var i = startY; i > stopY; i -= step) {             this.scrollTo(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; }  bootstrap(AppComponent) 

I created a plunk to show this example working: Plunk Example

like image 37
Alex J Avatar answered Sep 20 '22 02:09

Alex J