Lately, I've been immersed in developing a Single Page Application (SPA) using Angular 16, TypeScript, and The Movie Database (TMDB).
During the implementation of a movies search feature, I encountered an unexpected issue.
Within the
app\services\movie-service.service.ts
file, I have defined:
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';
@Injectable({
providedIn: 'root'
})
export class MovieService {
constructor(private http: HttpClient) {}
public searchMovies(searchTerm: string): Observable<MovieResponse> {
return this.http.get<MovieResponse>(`${environment.apiUrl}/search/movie?api_key=${environment.apiKey}&query=${searchTerm}`);
}
}
I am utilizing the above method within the TopBarComponent
in the following manner:
import { Component } from '@angular/core';
import { MovieResponse, Movie } from '../../models/Movie';
import { MovieService } from '../../services/movie-service.service';
@Component({
selector: 'app-top-bar',
templateUrl: './top-bar.component.html',
styleUrls: ['./top-bar.component.scss']
})
export class TopBarComponent {
constructor(private movieService: MovieService) { }
public searchTerm: string = '';
public isSearch: boolean = false;
public timeOutInterval: number = 500;
public searchResultsResponse!: MovieResponse;
public searchResults: Movie[] | undefined = [];
public hideSearchResults(): void {
this.isSearch = false;
}
public debounceMovieSearch(): void {
setTimeout(() => this.doMovieSearch(), this.timeOutInterval);
}
public doMovieSearch() {
if (this.searchTerm && this.searchTerm.length > 2) {
this.isSearch = true;
this.movieService.searchMovies(this.searchTerm).subscribe((response) => {
this.searchResultsResponse = response;
this.searchResults = this.searchResultsResponse.results;
})
} else {
this.isSearch = false;
}
}
}
Here is the structure of the search form implemented:
<form class="search_form w-100 mx-auto mt-2 mt-md-0">
<div class="input-group">
<input type="search" name="search" [(ngModel)]="searchTerm" (input)="debounceMovieSearch()" placeholder="Search" autocomplete="off" class="form-control search-box">
<button class="btn btn-search" type="button">Search</button>
</div>
<div *ngIf="isSearch" (clickOutside)="hideSearchResults()" class="search-results shadow-sm">
<div *ngIf="searchResults && searchResults.length">
<a routerLink="/movie/{{ movie.id }}" *ngFor="let movie of searchResults">
<app-search-item [movie]="movie"></app-search-item>
</a>
</div>
<div *ngIf="!(searchResults && searchResults.length)">
<p class="m-0 p-2 text-center">No movies found for this search</p>
</div>
</div>
</form>
The defined routes in the app\app-routing.module.ts
:
const routes: Routes = [
{ path: '', component: HomePageComponent, data: { title: 'Now playing' } },
{ path: 'top-rated', component: TopMoviesComponent, data: { title: 'Top Rated' } },
{ path: 'movie/:id', component: MovieDetailsComponent, data: { title: '' } },
{ path: 'actor/:id', component: ActorDetailsComponent, data: { title: '' } },
{ path: '**', component: NotFoundComponent, data: { title: '' } },
];
Visual representation of the outcome:
https://i.sstatic.net/iTkKJ2j8.png
The Dilemma
Upon clicking a movie item in the search results listing, the navigation to the movie details route (MovieDetailsComponent
) occurs, unless currently at a movie details page already.
Stackblitz Reference
For further examination, check out the code I have assembled so far on Stackblitz.
Inquiries
- What could be the potential error in my approach?
- What solution presents the most dependable fix to address this concern?