What is the best way to transfer information from a component to the routing module in Angular version 16?

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.

What is the most dependable approach to realize this objective?

Answer №1

To ensure you always have the most up-to-date post title content stored on the service, you can utilize a function called getFullTitle. However, it is important to remember that when the component is destroyed, you must set the service title to an empty string.

film by genre.com.ts

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 {
    // 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.postTitle = ` - ${this.genreName}`;
        }
      }
    });

    // Get movies by genre id
    this.movieService.getMoviesByGenre(genre_id).subscribe((response) => {
      this.movieResponse = response;
      this.movies = this.movieResponse.results;
    });
  }

  ngOnInit() {
    this.movieService.postTitle = '';
    this.getMoviesByGenre();
  }
}

app.com.html

<app-top-bar></app-top-bar>

<div class="container" [@routeAnimations]="prepareRoute(outlet)">
  <h1
    *ngIf="getFullTitle() as finalTitle"
    class="page-title text-success mt-2 mb-3"
  >
    {{ finalTitle }}
  </h1>
  <router-outlet #outlet="outlet"></router-outlet>
</div>

<app-footer class="mt-auto"></app-footer>

app.com.ts

import { Component } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { RouterOutlet } from '@angular/router';
import { slider } from './route-animations';
import { MovieService } from './services/movie-service.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  animations: [slider],
})
export class AppComponent {
  public title: String = 'Movies';

  constructor(
    private route: ActivatedRoute,
    private router: Router,
    private movieService: MovieService
  ) {
    this.router.events.subscribe((event) => {
      if (event instanceof NavigationEnd && this.route.root.firstChild) {
        this.title = this.route.root.firstChild.snapshot.data['title'];
      }
    });
  }

  public getFullTitle() {
    return this.title + this.movieService.postTitle;
  }

  public prepareRoute(outlet: RouterOutlet) {
    return (
      outlet &&
      outlet.activatedRouteData &&
      outlet.activatedRouteData['animation']
    );
  }
}

Stackblitz Demo

Answer №2

After reworking your code in multiple places, I have made necessary changes. Feel free to take a look at the updated Stackblitz Demo. Detailed comments are added within most files to guide you on enhancing your code further.

Your previous code remains intact for comparison purposes against the refactored version.

Please review each file or seek out new comments to refine your code even more.

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

NextJS VSCode Typescript results in breakpoints becoming unbound

I have been following the instructions provided by Next.js from their official documentation on debugging using Visual Studio Code found here: https://nextjs.org/docs/advanced-features/debugging#using-the-debugger-in-visual-studio-code When attempting to ...

Most secure methods to safeguard videos from unauthorized downloading

How can I increase the security measures to prevent users from easily downloading videos from my website? While I understand that it is impossible to completely stop downloads, I am looking for ways to make it more challenging than just a simple right-cl ...

Error in Angular: Unable to find a provider for the dependency of a dependency

Currently, I am in the process of developing a small toy application in Angular that consists of various classes, including ProductDetailComponent and ProductService. The ProductService class contains a method responsible for making an HTTP GET request for ...

Choose between using Paypal or Google Checkout for your shopping cart - unfortunately, both options cannot be used

My dilemma is that I currently have a functional shopping cart that is only coded for either Paypal or Google Checkout, not both. Here is a demo of the shopping cart set up for Paypal checkout: The javascript code used in the demo can be found here: Loo ...

Tips for implementing React Browser Router within Material UI Drawer

I'm currently exploring how to implement Browser Router in React to populate the content section of a Material UI Drawer. While my code successfully links menu options to components displayed within the drawer's content section, a problem arises ...

Issue with AJAX not properly executing predefined function when trying to fetch data from database using PDO

When integrating this section into an HTML form and working with PHP for the server-side backend, the goal is to allow users to select a country and have the city list refined to show only cities within that particular country. While AJAX is successfully r ...

I would like to fade out every element except for the one with the class "this

I need a solution where every div with the class "insegnanti" fades out, except for the one that I clicked on. Here is the script: for(var i=0;i<instructor.length;i++){ $(document).on ("click", ".insegnanti#i"+[i+1], loadSingleIns); el+="<div cl ...

What is the best way to send a ref from forwardRef to a specialized hook in TypeScript?

I'm currently working on implementing the useIntersection hook in my code. Everything seems to be functioning correctly, but I've run into some issues with TypeScript: import { MutableRefObject, useEffect } from 'react'; export default ...

Attach a click event to a dynamically generated element inside a directive

After thinking I had successfully solved this issue, it turns out I was mistaken. I developed a directive to enable me to clear a text input field. Essentially, when you begin typing into the input box, an "X" icon appears on the right side of the textbox. ...

Modifying the color of the error icon in Quasar's q-input component: a step-by-step guide

https://i.stack.imgur.com/4MN60.png Is it possible to modify the color of the '!' icon? ...

Automated validation and submission within an Adobe PDF document

After clicking the "submit" button on my PDF form, I want to perform a specific action (such as making a field readonly) based on whether the form validation and submission processes are successful: if (form.isValid()) { submitForm(...); if (form. ...

Adjusting the z-coordinate of a 3D object in UseFrame

My current project involves creating a 3D animation with React and Three.js, where a car moves forward by decreasing its z position using the useRef hook. The animation stops when it reaches -100, but I'm having trouble resetting the z position to its ...

Having trouble with the updateOne() method in MongoDB - it's not updating my document nor displaying any errors. What could be the issue?

I'm currently facing an issue where I am attempting to update a user's document in the database with a value obtained from a calculator. However, despite not encountering any errors, the document does not seem to be updating and the page just con ...

Guidelines for utilizing regex to match this specific string

Hey guys, I need help with parsing this string (a url). example.html/#playYouTubeVideo=id[lBs8jPDPveg]&width[160]&height[90] I'm trying to extract the values for id, width, and height within brackets. This is what I've come up with: [ ...

Is the video failing due to excessive adjustments of the video's currentTime?

Utilizing both user drag event and keypresses to adjust the position in an HTML5 video element, I am updating the video time with the following line of code: video.currentTime = toTime; Additionally, I am updating a canvas based on the video's posit ...

What is the process for retrieving information from Sanity?

Having trouble with creating a schema and fetching data from sanity. The console log is showing undefined. Not sure where I went wrong but suspect it's related to the schema creation. Testimonials.tsx interface Props { testimonial: [Testimonial] ...

Tips for running a function at regular intervals in NodeJS

I've experimented with the setInterval() method before. While it seemed ideal, the problem I encountered was that it didn't start the first call immediately; instead, it waited for X seconds before producing the desired value. Is there an alterna ...

What sets apart utilizing a constructor versus state = {} for defining state in a react component?

There are two ways to declare state in a class component as shown below: class App extends Component { constructor(props) { super(props); this.state = { name: 'John' } } render() { return ...

The error with Bootstrap4 alpha6 modal is in the process of transitioning

Currently, I am facing an issue with the bootstrap4 alpha 6 modal. The error message I am receiving is: Error: Modal is transitioning This occurs when attempting to re-trigger the same modal with dynamic data using a JavaScript function like this: funct ...

JavaScript - Persistent memory retention issues

I've noticed persistent memory leaks in my TypeScript application (3PG), leading me to believe there's an issue with memory management. Comparison of Applications: 2PG -> https://github.com/theADAMJR/2pg [no memory leaks] 3PG -> the speci ...