如何将数据从组件发送到 Angular 16 中的路由模块?

问题描述 投票:0回答:1

我一直在使用 Angular 16、TypeScript 和电影数据库 (TMDB) 开发 SPA。

我制作了一个按类型显示电影的组件:

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 包含我迄今为止拥有的所有代码。

达到这个结果最可靠的方法是什么?

javascript angular typescript
1个回答
0
投票

您可以将帖子标题内容存储在服务上,并使用函数

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 演示

© www.soinside.com 2019 - 2024. All rights reserved.