Why do users struggle to move between items displayed within the same component in Angular 16?

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

  1. What could be the potential error in my approach?
  2. What solution presents the most dependable fix to address this concern?

Answer №1

You're on the right track, but one adjustment you need to make is using paramMap instead of snapshot in the movie-details.component, so that you can respond to changes in the movie id.

To implement this change, modify the getMovieDetails function as follows:

getMovieDetails(): void {
  this.activatedRoute.paramMap.pipe(
    map(params => params.get('id')), // extract id from route
    switchMap((id: string | undefined | null) => {
      if (id) return this.movieService.getMovieDetails(Number(id));
      return of(undefined); // return undefined if no id provided
   })
  ).subscribe((response: Movie | undefined) => {
     if (response) { // perform action if movie exists
        this.movie = response;
        // ...
     }
  })
}

Furthermore, remember that paramMap produces an observable, so it's crucial to only subscribe once. This is why I'm utilizing pipe and returning the final observable result containing either a Movie or undefined.

Answer №2

As you move from film/1 to film/2, the FilmDetailsComponent does not undergo a complete refresh. This is because it is not set up to actively monitor changes in the film id parameter, resulting in an outdated view. To address this issue, make sure to listen for route parameter modifications:

ngOnInit() {
  this.activatedRoute.paramMap.subscribe(paramMap => {
    const film_id = Number(paramMap.get('id'));
    this.getFilmDetails(film_id);
  });
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Cryptocurrency price tracker with sleek Bitcoin symbol and FontAwesome icons

My assignment involved creating a function that retrieves Bitcoin trades from a JSON URL, allows users to change the interval with buttons, uses fontawesome arrows to indicate rate changes (up/down/no change), and displays the data on a website. Everythin ...

Error: The XML parsing in ASP failed to find a root element at the specified location

When clicking the button, I have jQuery/Ajax code that is supposed to pass the value of a selected radio button to a controller action and open a detail page. However, I am encountering an error. When using Mozilla Firefox, the console displays: XML Par ...

Troubleshooting a Vue.js formatting problem in Visual Studio 2019

Encountering an issue with VS2019 while attempting to format this code section. <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="milestone.ascx.cs" Inherits="uc.dms.milestone" %> <section class="content-header"> <h1> ...

I am facing an issue where this loop is terminating after finding just one match. How can I modify it to return

I am currently working with an array that compares two arrays and identifies matches. The issue is that it only identifies one match before completing the process. I would like it to identify all matches instead. Can anyone explain why this is happening? ...

"Troubleshooting Angular 2 Directives That Cause Errors

Hey there, I'm currently working on understanding ANGULAR 2 routing, but I've encountered an error that's causing some trouble. Here's the issue I'm facing: app/app.component.ts(7,12): error TS2345: Argument of type '{ s ...

What is the best way to clear radio button selections in a form using reactjs?

I designed a survey form with 4 radio buttons for a single question. I also included buttons to submit the form and clear input fields. However, when I click on "Clear Input," the checked radio buttons do not get cleared. How can I achieve this using the r ...

What is the best method for embedding my token within my user entity?

Currently, I am working on implementing a "forgot password" feature in my application. The idea is that when a user requests to reset their password, they will receive a token via email that expires after two hours. To prevent the generation of multiple to ...

Adjusting the starting point on a 2D canvas with EaselJS translation

When using plain javascript, I was able to change the origin of the canvas to the center by following these steps: var canvas = document.getElementById('canvas'); var context = canvas.getContext('2d'); canvas.width = 1024; canvas.heigh ...

Encountering issues in d3.js following the transition to Angular 8

After upgrading my Angular 4 app to Angular 8, I encountered an issue where the application works fine in development build but breaks in production build. Upon loading the application, the following error is displayed. Uncaught TypeError: Cannot read p ...

What is the best way to specify parameter names and types for a TypeScript function that can take either one or two arguments?

Looking to create a function with two different calling options: function visit(url: string, options: Partial<VisitOptions>): void function visit(options: Partial<VisitOptions> & {url:string}): void I'm exploring the most effective w ...

Removing sourceMappingURL from an Angular Universal build: A step-by-step guide

Using this repository as my foundation, I have successfully resolved most of the plugin errors except for one that continues to elude me. It's puzzling because no other plugin anticipates a .map file in an SSR build since it is intended for productio ...

Enhancing Date formatting in Jquery Data tables following ASP.NET Serialization

Currently, I am facing an issue with formatting dates in a SQL database query that is being serialized by ASP and then converted to JSON for display in Datatables using JavaScript. Instead of the correct date format, I am seeing: /Date(1424563200000)/. I ...

Strategies for eliminating the 'hoek' vulnerabilities

I recently uploaded an Angular CLI 5 project to GitHub and received the following security alert: A security vulnerability was found in one of the dependencies used in net-incident/package-lock.json. It is recommended to update this dependency to address ...

Limit the options in jQuery UI auto-complete to search by name from a variety of JSON responses

I am looking to enhance my search functionality by utilizing jqueryUi's auto-complete feature to specifically target Names and exclude other array values such as fax. Here is how I have implemented it in php: <?php require_once 'db_conx.php&a ...

switch the visibility of the p tag based on its content

It seems like solving this shouldn't be too challenging, but I'm still learning when it comes to Javascript or JQuery. HTML: <p><span id="AddLine1Summary"></span>,</p> <p><span id="AddLine2Summary"></span& ...

Scroll to make the div slide in from the bottom

I'm trying to achieve a similar effect like the one shown in this website (you need to scroll down a bit to see the divs sliding in). Although I'm not very proficient in JS, I was able to create a code that makes the divs fade in from 0 opacity ...

Height Setting for Angular Material Buttons

html: <body id="app"> <md-button> Yo </md-button> </body> Looks: Why is the button set to 100% height? It should look like an inline element according to the materials documentation here. Also, why aren't the materi ...

Exploring the functionality of this TypeScript code: What's the distinction between { [key: string]: string }[] and { prop1: string, prop2: string }[]

Below is the code I am currently working with: get tags(): { [key: string]: string }[] { let tags: { [key: string]: string }[] = []; if(this.tags) { Object.keys(this.tags).forEach(x => { tags.push({ prop1: this.tags[x], prop2: g ...

Obtain the computed style by utilizing setTimeout for effective functionality

I want to retrieve the calculated style (background-color) of a span element. Here's my HTML code, consisting of two label elements, each containing an input and a span: <label> <input type="radio" name="numbers" value="01" checked/> ...

I encountered a warning while using the useViewportScroll in NextJs with Framer Motion: "Caution: The useLayoutEffect function does not have any effect on the server

Successfully implementing NextJs with Framer Motion, yet encountered a warning: Warning: useLayoutEffect does not function on the server due to its effect not being able to be encoded in the server renderer's output format. This may cause a differenc ...