Как я могу отправить данные из компонента в модуль маршрутизации в Angular 16?

Я работал над SPA с Angular 16, TypeScript и The Movie Database (TMDB).

Я сделал компонент, который отображает фильмы по жанрам:

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;
        }
      }
    });

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

  ngOnInit() {
    this.getMoviesByGenre();
  }
}

В сервисе, используемом вышеуказанным компонентом, у меня есть:

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}`);
  }
}

В модуле маршрутизации у меня есть:

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' },
  },
];

Из модуля маршрутизации, если свойство title в объекте data не пусто, я отображаю заголовок страницы в 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>

Для MoviesByGenreComponent я хочу отправить динамически полученное название жанра (переменная genreName) из компонента в маршрутизатор и присвоить genreName свойству title.

Желаемый результат:

Стекблиц

Есть stackblitz со всем имеющимся у меня кодом.

Каков наиболее надежный способ достичь этого результата?

В общем, Angular предоставляет различные способы обмена данными между компонентами . В вашем случае у вас должна быть возможность поделиться своими genreName данными из дочернего компонента MoviesByGenreComponent с родительским компонентом AppComponent как отношение родитель-потомок, описанное в следующем разделе: Обмен данными между дочерними и родительскими директивами и компонентами

Lecram 27.04.2024 23:39
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
1
161
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете сохранить содержимое заголовка сообщения в сервисе и использовать функцию getFullTitle, чтобы всегда получать последнее значение. Единственное предостережение в отношении этого подхода — вам необходимо убедиться, что заголовок сервиса устанавливается в пустую строку каждый раз, когда компонент уничтожается!

фильм жанра.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

Пожалуйста, ознакомьтесь с обновлением вопроса. Спасибо!

Razvan Zamfir 29.04.2024 10:46

@RazvanZamfir, на мой взгляд, это лучший подход: мы не можем обновить родительский маршрутизатор, вместо этого мы можем просто использовать службу и отображать заголовок на основе переменной службы. Я не уверен, что не так с моим подходом!

Naren Murali 29.04.2024 17:27

В этом нет ничего плохого, но это может быть немного слишком сложно. Я оставлю вопрос открытым, на случай, если появятся лучшие идеи. Если их нет, я применю этот.

Razvan Zamfir 29.04.2024 21:45

Я рефакторил ваш код в нескольких местах. Демо-версия Stackblitz была соответствующим образом обновлена. Большинство файлов содержат комментарии о том, как можно улучшить свой код.

Я не удалил ваш предыдущий код, чтобы вы могли сравнить его с отрефакторенной версией.

Проверяйте каждый файл или ищите новые комментарии.

Другие вопросы по теме