Currently, I have been developing a Single Page Application (SPA) using Angular 16, TypeScript, and integrating The Movie Database (TMDB).
One of the components I've built displays movies based on genre:
import { Component } from '@angular/core';
import { GenreResponse, Genre } from '../../models/Genre';
import { MovieResponse, Movie } from '../../models/Movie';
import { MovieService } from '../../services/movie-service.service';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-movies-by-genre',
templateUrl: './movies-by-genre.component.html',
styleUrls: ['./movies-by-genre.component.scss']
})
export class MoviesByGenreComponent {
public movieResponse!: MovieResponse;
public movies: Movie[] | undefined = [];
public genreResponse!: GenreResponse;
public genres: Genre[] | undefined = [];
public genreName: string | undefined = '';
constructor(
private activatedRoute: ActivatedRoute,
private movieService: MovieService
) { }
public getMoviesByGenre(): void {
// Retrieve genre id from URL parameter
const genre_id = Number(this.activatedRoute.snapshot.paramMap.get('id'));
// Obtain 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;
}
}
});
// Fetch movies by genre id
this.movieService.getMoviesByGenre(genre_id).subscribe((response) => {
this.movieResponse = response;
this.movies = this.movieResponse.results;
})
}
ngOnInit() {
this.getMoviesByGenre();
}
}
In the service that is utilized by the above component, I include:
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';
import { TrailerResponse } from '../models/Trailer';
@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}`);
}
}
Within the routing module, I have defined:
const routes: Routes = [
{
path: '',
component: HomePageComponent,
data: { title: 'Now playing', animation: 'isRight' },
},
{
path: 'by-genre/:id',
component: MoviesByGenreComponent,
data: { title: '', animation: 'isLeft' },
},
{
path: 'movie/:id',
component: MovieDetailsComponent,
data: { title: '', animation: 'isLeft' },
},
{
path: 'actor/:id',
component: ActorDetailsComponent,
data: { title: '', animation: 'isRight' },
},
{
path: '**',
component: NotFoundComponent,
data: { title: '', animation: 'isRight' },
},
];
If the title
property in the data
object is not empty within the routing configuration, the page title is displayed accordingly in app\app.component.html
:
<div class="container">
<h1 *ngIf="title.length" class="page-title text-success mt-2 mb-3">{{ title }}</h1>
<router-outlet></router-outlet>
</div>
To achieve the desired outcome for the MoviesByGenreComponent
, it's essential to pass the dynamically acquired genre name (stored in the variable genreName
) from the component to the router and set genreName
as the value for the title
property.
The end goal:
https://i.sstatic.net/e81xFFFv.png
Stackblitz
A comprehensive view of the code progress can be found in this stackblitz.