🚀 Building an Infinite Scroll with Angular and .NET Core API

Infinite scroll is a popular UX pattern where more data loads automatically as you scroll down a page, no need for pagination buttons. In this blog post, we’ll walk through how to implement infinite scrolling in an Angular app, powered by a paginated .NET Core API.

🔧 Tech Stack

  • Frontend: Angular 14+ (TypeScript, HTML, CSS)

  • Backend: ASP .NET Core Web API (.NET 6 or 7)

  • HTTP Client: Angular HttpClient

🧱 Project Overview

We’ll build:

  • A .NET Core API that serves a paginated list of items

  • An Angular component that displays these items in a scrollable container

  • A scroll event handler that triggers additional API calls as you scroll

1️⃣ Create the .NET Core Backend

Start by setting up a simple Web API project:

🔹 Sample Controller: ItemsController.cs

[ApiController]
[Route("api/[controller]")]
public class ItemsController : ControllerBase
{
    private static readonly List<string> AllItems = Enumerable.Range(1, 1000)
        .Select(i => $"Item {i}")
        .ToList();

    [HttpGet]
    public IActionResult GetItems(int page = 1, int pageSize = 20)
    {
        var items = AllItems
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToList();

        return Ok(items);
    }
}

This endpoint returns 20 items at a time by default.

🔹 Enable CORS (Optional if frontend and backend are separated)

In Program.cs:

builder.Services.AddCors(options =>
{
    options.AddDefaultPolicy(policy =>
    {
        policy.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
    });
});
app.UseCors();

2️⃣ Set Up the Angular Project

Use Angular CLI:

ng new infinite-scroll-demo
cd infinite-scroll-demo
ng generate component infinite-scroll
ng generate service item

3️⃣ Create the Angular Service

📄 item.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class ItemService {
  private apiUrl = 'https://localhost:5001/api/items';

  constructor(private http: HttpClient) {}

  getItems(page: number, pageSize: number): Observable<string[]> {
    return this.http.get<string[]>(`${this.apiUrl}?page=${page}&pageSize=${pageSize}`);
  }
}

Make sure HttpClientModule is imported in your AppModule.


4️⃣ Create the Infinite Scroll Component

📄 infinite-scroll.component.ts

import { Component, OnInit } from '@angular/core';
import { ItemService } from '../item.service';

@Component({
  selector: 'app-infinite-scroll',
  templateUrl: './infinite-scroll.component.html',
  styleUrls: ['./infinite-scroll.component.css']
})
export class InfiniteScrollComponent implements OnInit {
  items: string[] = [];
  page = 1;
  pageSize = 20;
  isLoading = false;
  endOfData = false;

  constructor(private itemService: ItemService) {}

  ngOnInit() {
    this.loadItems();
  }

  loadItems() {
    if (this.isLoading || this.endOfData) return;
    this.isLoading = true;
    this.itemService.getItems(this.page, this.pageSize).subscribe(data => {
      if (data.length === 0) {
        this.endOfData = true;
      } else {
        this.items.push(...data);
        this.page++;
      }
      this.isLoading = false;
    });
  }

  onScroll(event: any): void {
    const target = event.target;
    const atBottom = target.scrollTop + target.clientHeight >= target.scrollHeight - 50;

    if (atBottom) {
      this.loadItems();
    }
  }
}

📄 infinite-scroll.component.html

<div class="container" (scroll)="onScroll($event)">
  <div *ngFor="let item of items" class="item">
    {{ item }}
  </div>

  <div *ngIf="isLoading" class="loading">Loading...</div>
  <div *ngIf="endOfData" class="end">No more items</div>
</div>

📄 infinite-scroll.component.css

.container {
  width: 400px;
  margin: auto;
  height: 80vh;
  overflow-y: auto;
  border: 1px solid #ccc;
  padding: 10px;
}

.item {
  padding: 10px;
  border-bottom: 1px solid #ddd;
}

.loading, .end {
  text-align: center;
  padding: 10px;
  color: gray;
}

🔁 How It Works

  • On initialization, the component fetches the first page of items.

  • When the user scrolls near the bottom of the container, it fetches the next page.

  • It stops loading when the API returns an empty array.


🧪 Tips for Real Projects

  • Handle error states in the UI

  • Integrate a loading spinner

  • You can also use ngx-infinite-scroll if you prefer a library

  • You can reuse the same backend and logic to implement infinite scroll in a custom dropdown.


✅ Conclusion

We’ve built a fully functional infinite scroll component using Angular and .NET API pagination. This setup gives you full control and a clean separation of frontend and backend responsibilities.


🔗 Resources

0
Subscribe to my newsletter

Read articles from Pranali Kulkarni directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Pranali Kulkarni
Pranali Kulkarni