导致 Angular 16 中同一组件呈现的项目之间导航失败的原因是什么?

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

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

我在开发电影搜索功能时遇到了一个奇怪的问题。

app\services\movie-service.service.ts
我有:

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

我在

TopBarComponent
中使用上面的方法,如下所示:

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

搜索表格:

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

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

结果如下所示:

enter image description here

问题

单击搜索结果列表中的电影项目将导航至电影详细信息路线 (

MovieDetailsComponent
),除了当我们已经位于电影详细信息页面时

堆栈闪电战

有一个 Stackblitz 包含我迄今为止拥有的所有代码。

问题

  1. 我做错了什么?
  2. 解决此问题最可靠的方法是什么?
javascript angular typescript
2个回答
0
投票

你几乎是正确的,你缺少的是在

paramMap
中使用
snapshot
而不是
movie-details.component
,这样你就可以对电影
id
的变化做出反应。

您需要在函数

getMovieDetails
上解决此更改,如下所示:

getMovieDetails(): void {
  this.activatedRoute.paramMap.pipe(
    map(params => params.get('id')), // retrieve id from route
    switchMap((id: string | undefined) => {
      if (id) return this.movieService.getMovieDetails(Number(id));
      return of(undefined); // if there is no id, then return undefined
   })
  ).subscribe((response: Movie | undefined) => {
     if (response) { // if movie exists then do something...
        this.movie = response;
        // ...
     }
  })
}

0
投票

当您从

movie/1
导航到
movie/2
时,不会重新创建
MovieDetailsComponent
。因为您不监听 id 更改,所以组件不知道电影 id 已更改,并且需要更新视图。所以监听路由参数变化:

ngOnInit() {
  this.activatedRoute.paramMap.subscribe(paramMap => {
    const movie_id = Number(paramMap.get('id'));
    this.getMovieDetails(movie_id);
  });
}
© www.soinside.com 2019 - 2024. All rights reserved.