I have been working on an SPA with Angular 16, TypeScript and The Movie Database (TMDB).
I am atempting to make an “infinite scroll” feature on one of the components with Angular Virtual Scroll.
For this purpose, I have imported the ScrollingModule
and added it to the imports
array in appapp.module.ts
.
In appservicesmovie-service.service.ts
I have:
import { environment } from '../../environments/environment';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { MovieResponse, Movie } from '../models/Movie';
import { GenreResponse } from '../models/Genre';
@Injectable({
providedIn: 'root'
})
export class MovieService {
constructor(private http: HttpClient) { }
public getAllMovieGenres(): Observable<GenreResponse> {
return this.http.get<GenreResponse>(`${environment.apiUrl}/genre/movie/list?api_key=${environment.apiKey}`);
}
public getMoviesByGenre(id: Number): Observable<MovieResponse> {
return this.http.get<MovieResponse>(`${environment.apiUrl}/discover/movie?api_key=${environment.apiKey}&with_genres=${id}`);
}
}
In the MoviesByGenre
component I have:
export class MoviesByGenre {
constructor(
private activatedRoute: ActivatedRoute,
private movieService: MovieService
) { }
public genreName: string | undefined = '';
public movieResponse!: MovieResponse;
public movies: Movie[] | undefined = [];
public genreResponse!: GenreResponse;
public genres: Genre[] | undefined = [];
public getMoviesByGenre(): void {
// Get genre id (from URL parameter)
const genre_id = Number(this.activatedRoute.snapshot.paramMap.get('id'));
// Get genre name from genres array
this.movieService.getAllMovieGenres().subscribe((response) => {
this.genreResponse = response;
this.genres = this.genreResponse.genres;
if (this.genres && this.genres.length) {
let currentGenre = this.genres.find(genre => genre.id === genre_id);
if (currentGenre) {
this.genreName = currentGenre.name || '';
this.movieService.defaultTitle = this.genreName;
}
}
});
// Get movies by genre id
this.movieService.getMoviesByGenre(genre_id).subscribe((response) => {
this.movieResponse = response;
this.movies = this.movieResponse.results;
})
}
ngOnInit() {
this.activatedRoute.params.subscribe((params: Params) => {
const id = params?.['id'];
this.getMoviesByGenre();
});
}
ngOnDestroy() {
this.movieService.defaultTitle = '';
}
}
In the component’s template:
<ng-container *ngIf="movieResponse">
<div class="row grid">
<cdk-virtual-scroll-viewport itemSize="auto">
<div *cdkVirtualFor="let movie of movies" class="col-xs-12 col-sm-6 col-lg-4 col-xl-3">
<app-movie-card class="movie card" [movie]="movie" [showGenres]="false"></app-movie-card>
</div>
</cdk-virtual-scroll-viewport>
</div>
</ng-container>
As can be seen above, I do not have all the items in the movies
arary available from the start.
Further more, the initial 20 movies that would be displayed in the absence of <cdk-virtual-scroll-viewport>
are not displayed at all.
What am I doing wrong?