This tutorial is out of date and no longer maintained.
When dealing with a large amount of content, you may find it useful to add an infinite scroll feature to your site. When I say infinite scrolling, I’m referring to a page appending new content as the user continues to scroll, giving the page the illusion of scrolling indefinitely. Loads of websites use this feature, and it can be a fluid alternative to something like pagination.
While there are myriad different ways to implement this, let’s explore how we can accomplish this using the Angular Component Dev Kit (CDK).
Let’s start by adding the @angular/cdk
package to our project:
To leverage the infinite scrolling functionality in this package, import ScrollingModule
to your app.module.ts
:
Then add it to your imports:
You’re now ready to start!
We’re going to build a component that displays random historical events. When the user reaches the end of the scroll, our application will load more facts.
For the purpose of this tutorial, I’m going to gloss over the details of building the service.
For the time being, assume that we have a FactService that only provides the following function:
We’ll be pulling 10 facts at a time, and each time the user scrolls to the end, we’ll query for 10 more facts.
FactScrollerComponent
Construct a new component that will act as your infinite scroller. I’m calling mine FactScrollerComponent
. You can use the Angular CLI to do this:
Ensure that the new component is imported to your app.module.ts
:
And added to the declarations:
In our fact-scroller.component.html
let’s construct the scroller scaffolding:
Here we use a cdk-virtual-scroll-viewport
to be our virtual scroller. Within this, we loop over our items using *cdkVirtualFor
, which is analogous as using *ngFor
.
In order for the component to properly size its internal scroller, we need to tell the scroller how tall each item will be (in pixels). This is done using the itemSize
directive. So, itemSize="100"
means that item in the list will require 100px of height.
We’ve also told the scroller to pull the data from dataSource
, which doesn’t exist yet, so it’s best we create it now.
FactsDataSource
In our fact-scroller.component.ts
file, we need to define what our data source looks like. To do this, we’ll extend the DataSource
class in @angular/cdk/collections
. Here’s what our data source looks like:
There’s a lot to digest here, so let’s break it down.
We first define our model, Fact
, which will define our data structure.
Within FactsDataSource
, we need to implement two functions: connect()
, and disconnect()
. The data source is subscribed to any changes in the collection viewer (e.g., the user scrolls), and will then perform an action and return the data stream. We are going to tell the data source to get more data when we have reached the end of the list.
We also declared three member variables:
cachedFacts
: our cached results,dataStream
: a RxJS BehaviorSubject to propagate changes to our cached results, andsubscription
: a subscription to listen for view collection changes.Let’s define a few helpers within this class:
I’m setting the page size to 10, meaning I want to grab 10 facts at a time. I’m also going to keep track of the last page loaded.
_fetchFactPage()
makes a call to our service to get some facts, which are then appended to the cache.
_getPageForIndex()
will convert an line index to a page (or batch) value.
Putting these all together, we can then define how we want the list to update within the subscription callback:
We also want to start with some data, so we can make a call to our fetch function in the constructor:
Our custom data source should now get us where we need to go. The final piece to put it all together is to add our new data source to the component.
And we’re done! Everything from here on out is formatting. I’ve rewritten my HTML to display the facts like so:
Happy Scrolling!
Continue your learning with the Angular CDK documentation.
You can find the complete source code for this example project in this repo GitHub.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
nice article, ty :)
but for real, this:
private cachedFacts = Array.from<Fact>({ length: 0 });
instead of this? :)
private cachedFacts: Array<Fact> = []