Coding exercise: implement infinite scrolling in Angular.

Angular practical coding · Freshers and experienced

Model answer

Watch a sentinel element at the end of the list with IntersectionObserver and load the next page when it appears. Clean up the observer when the component is destroyed.

@Component({
  selector: 'app-feed',
  template: `
    <ul>@for (x of items(); track x.id) { <li>{{ x.title }}</li> }</ul>
    <div #end>{{ busy() ? 'Loading…' : done() ? 'No more items.' : '' }}</div>`,
})
export class Feed implements AfterViewInit, OnDestroy {
  private http = inject(HttpClient);
  items = signal<{ id: number; title: string }[]>([]);
  busy = signal(false);
  done = signal(false);
  private page = 0;
  private io?: IntersectionObserver;
  end = viewChild<ElementRef<HTMLElement>>('end');

  ngAfterViewInit() {
    this.load();
    this.io = new IntersectionObserver(([e]) => e.isIntersecting && this.load(), { rootMargin: '200px' });
    this.io.observe(this.end()!.nativeElement);
  }
  load() {
    if (this.busy() || this.done()) return;
    this.busy.set(true);
    this.http.get<{ items: { id: number; title: string }[] }>('/api/posts', { params: { page: ++this.page, limit: 20 } }).subscribe({
      next: (d) => { this.items.update((l) => [...l, ...d.items]); if (d.items.length < 20) this.done.set(true); this.busy.set(false); },
      error: () => this.busy.set(false),
    });
  }
  ngOnDestroy() { this.io?.disconnect(); }
}

Trade-offs to mention: offer a "Load more" button for keyboard users, and use the CDK virtual scroll for very long lists.

Tips

Practise it yourself in the React and Angular code playground.

Learn this topic

Angular Tutorial: Beginner to Advanced .

Sign in to add your own answer.

More questions