Home > Software engineering >  Angular 14 how to use async pipe with specific field in json response?
Angular 14 how to use async pipe with specific field in json response?

Time:10-16

Hello friendly early birds!

I fetch data from an API with following response:

enter image description here

My service returns the Observable<Movie[]> object to my component. In the HTML of the component, I want to use the async pipe instead of subscription. So I don't have to unsub on the components to prevent memory leaks.

movie-list.component.html:

<div >
  <div  *ngFor="let movie of movies$ | async">
    <app-movie
      [movie]="movie"
    ></app-movie>
  </div>
</div>

movie-list.component.ts:

export class MovieListComponent implements OnInit {

  movies$!: Observable<Movie[]>;

  constructor(private movieService: MovieService) { }

  ngOnInit(): void {
    this.movies$ = this.movieService.getMostPopularMovies();
  }
}

movie-service.ts:

})
export class MovieService {

  private apiKey: string = environment.apiKey;
  private apiMostPopularMovies: string = 'https://api.themoviedb.org/3/movie/popular';

  constructor(private http: HttpClient) { }

  getMostPopularMovies(): Observable<Movie[]> {
    let params = new HttpParams();
    params = params.set('api_key', this.apiKey);

    return this.http.get<Movie[]>(this.apiMostPopularMovies, {params});
  }
}

Movie.component.ts:

export class MovieComponent implements OnInit {

  @Input() movie!: Movie;

  constructor() { }

  ngOnInit(): void {
  }
}

My Movie model just have a title, poster_path and vote_average field. The field have the same names as the the response in results array have. I don't need anything else from the response.

Somehow I have to map the fields from the response from results array to my Movie model. Can someone explain how to do this with async pipe?

CodePudding user response:

Well, the problem is your response actually is not Movie[] but your response.results is.

To solve this, you could use map operator in rxjs. If you could use the following code in your service, async pipe would work fine.

export class MovieService {

  private apiKey: string = environment.apiKey;
  private apiMostPopularMovies: string = 'https://api.themoviedb.org/3/movie/popular';

  constructor(private http: HttpClient) { }

  getMostPopularMovies(): Observable<Movie[]> {
    let params = new HttpParams();
    params = params.set('api_key', this.apiKey);

    return this.http
               .get<{results: Movie[]}>(this.apiMostPopularMovies, {params})
               .pipe(map(response => response.results));
  }
}

CodePudding user response:

If I understood you correctly, you can try this in your service:

mappedMoviesObs: Observable<Movies[]> = this.getMostPopularMovies().pipe(
  map((movies: Movies[]) => movies.forEach((movie) => { // do mapping})
);

And in html use mappedMoviesObs instead of movies$.

  • Related