@angular/cli: 15.2.8
Source: GitHub
In this article I would like to talk about an often-used feature on a user-centric application - the scroll-to-top button for allowing a user to quickly scroll to the top of the page, without having to use the mouse. The end result would be something like this:
Let's break up this implementation into 3 steps:
✔️ Set up the scroll-to-top button (with some nice styling).
✔️ Determine when the button should be displayed.
✔️ Scroll to the top of the page on clicking the button.
Set up the scroll-to-top button:
I have used @angular/material for some easy styling. In order to display the button fixed to the bottom-right corner of the page (and some nice hover effects with opacity), I have used the below properties on the :host -
Determine when the button should be displayed:
This is an interesting section. To begin with, we need to set up an Observable
on the scroll event of the DOCUMENT
. You may directly access the document object, or you may use an InjectionToken<Document>
, provided by angular.
This observable starts emitting values as soon as the user starts to scroll up or down. Now we are not really interested in the actual scroll event, but we would like to check something important every time the scroll event is fired - and that is the scroll position. Angular makes this quite simple with the ViewportScroller
service from @angular/common
package. This service has few useful methods, and I am going to use two of them - getScrollPosition
and scrollToPosition
.
The getScrollPosition
method returns an array of 2 numbers - the X and Y coordinate. I check if the Y coordinate is more than 0 (which means the user has scrolled down) and I enable the scroll-to-top button.
Scroll to the top of the page on clicking the button:
For this last part, I make use of the scrollToPosition
method, which again takes in the X and Y coordinates, and I scroll to [0, 0].
UPDATE
The source code has been updated to angular 15, with standalone components. The main branch contains the updated syntax of angular 15. Refer to the legacy branch to view the old syntax of angular 13.
Cheers :-)
Anirban Mukherjee
Top comments (6)
OK I've solved the problem. Remove DOCUMENT and replace 'this.document' with 'window'. With that change it works great! Thanks for the article.
@rvwilliams88 sorry for a late reply. Unfortunately none of my machines has a v15 set up, so I can't really say what's wrong with the original approach. But if I had to give you a work-around then I would have done it the way you have. Nice that you figured it out yourself. But as always be careful while using the window object. Protect it using the
isPlatformBrowser
check as it may break on server-side rendering.This doesn't work for me. I'm on Angular 15. In showScroll$, this.document is marked as an error with the message
Property 'document' is used before its initialization.ts(2729)
viewer.component.ts(35, 15): 'document' is declared here.
Line 35 includes
@Inject(DOCUMENT) private readonly document: Document,
I'm not able to find a way around this. Can you help?
Can you please explain the benefit of putting the actual scrolling logic outside the ScrollComponent?
No honestly there isn't. It is your choice tbh. You can choose to consider the scroll-component as a specific button, which emits an event on click. Or you can choose to put all scroll related logic inside the component.
I have done both, depending on whether I am creating the component as part of a library or as a standalone component in a monorepo.
Works fine, without any issues on:
"@angular/core": "^16.1.0",