Search code examples
javascriptangularangular-routing

How can I configure my <li> items with Angular Routing so that it shows the relevant details in a new view?


I am building an Angular Movie DB, the two components I am working with are the "search-movie" component and the "single-view" component. The "search-movie" component displays a list of movies, the "single-view" component shows further details of a given movie.

I would like it so that when I click on a movie from the list in the "search-movie" component, the page renders the "single-view" component for that movie.

I have managed to set this up so that navigating to the "single-view" path with a movie id (i.e. /movie/tt4425200) directly from the URL, correctly loads up the info for that movie by it's ID, so that's all correctly set up.

I just can't seem to connect the clicking of a movie in the "search-movie" component, to then successfully navigate to the correct "single-view" path. So using the example above, clicking on the relevant movie loads up the "single-view" component with the URL path /movie/tt4425200.

I'm sure that this is a case of using @Input to communicate between the two components, but I just can't figure it out.

search-movie.component.ts:

import { Component, OnInit, Input } from '@angular/core';
import { FormControl } from '@angular/forms';

import { DataService } from '../data.service';

@Component({
  selector: 'app-search-movie',
  templateUrl: './search-movie.component.html',
  styleUrls: ['./search-movie.component.css']
})
export class SearchMovieComponent implements OnInit {

  searchControl = new FormControl('');
  movieResults: any = [];

  constructor(private data: DataService) { }

  ngOnInit() {}

  /* GET request */
  getData(event) {
    const film = event.target.value;
    this.data.searchFilm(film)
    .subscribe( (res) => {
      res = this.movieResults = res;
      console.log(res);
    });
  }
}

search-movie.component.html:

<div class="container">
    <h1 class="is-size-3">Find your favorite movies...</h1>
    <form (ngSubmit)="onSubmit()">
        <input 
            type="text" 
            (keyup)="getData($event)" 
            placeholder="Start typing..." 
            [formControl]="searchControl" />
    </form>
    {{searchControl.value}}
</div>

<div class="container">
    <ul>
        <li id="list-item" *ngFor="let x of movieResults; let i = index;">
            <img [src]="x.Poster" onerror="this.src='../assets/images/default-poster.jpg'">
            <p id="movie-title" class="is-size-5">{{x.Title}} ({{x.Year}}) </p>
        </li>
    </ul>
</div>

single-view.component.ts:

import { Component, OnInit, Input } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

import { DataService } from '../data.service';

@Component({
  selector: 'app-single-view',
  templateUrl: './single-view.component.html',
  styleUrls: ['./single-view.component.css']
})
export class SingleViewComponent implements OnInit {

  singleDetails: any = {};

  constructor(
    private data: DataService,
    private route: ActivatedRoute) { }

  ngOnInit() {
    /** GENERATE FILM DETAILS BY movie/id where id is the imdbID */
    const id = this.route.snapshot.paramMap.get('id');
    this.data.moviebyID(id)
    .subscribe( (res) => {
      res = this.singleDetails = res;
    });
  }

}

single-view.component.html:

<div class="container singleDisplayContainer">
    <div class="columns is-mobile">
        <div class="column" id="poster-column">
            <img id="poster" [src]="singleDetails.Poster" [alt]="singleDetails.Title" onerror="this.src='../assets/images/default-poster.jpg'">
        </div>
        <div id="info-column" class="column">
            <div class="columns">
                <div class="column is-three-fifths">
                    <h1 class="is-size-3">{{singleDetails.Title}} <span class="is-size-4">({{singleDetails.Year}})</span> </h1>
                    <p style="font-size: 14px"> {{singleDetails.Rated}} | {{singleDetails.Runtime}} | {{singleDetails.Genre}} | {{singleDetails.Released}} </p>
                </div>
                <div class="column">
                    <div class="columns">
                        <div class="column is-one-third">
                            <img id="star-rating" width="50px" src="../../assets/images/star-rating.png" alt="{{singleDetails.Title}}">
                        </div>
                        <div class="column">
                            <p style="font-size: 2em"> {{singleDetails.imdbRating}}<span style="font-size: 12px">/10</span></p>
                            <p>{{singleDetails.imdbVotes}}</p>
                        </div>
                    </div>
                </div>
            </div>

            <br>
            <p>Plot: {{singleDetails.Plot}} </p>
            <br>
            <p>Directed by: {{singleDetails.Director}} </p>
            <br>
            <p>Writers: {{singleDetails.Writer}} </p>
            <br>
            <p>Actors: {{singleDetails.Actors}} </p>
            <br>
            <p onerror="this.style.display='none'">Box office: {{singleDetails.BoxOffice}} </p>
        </div>
    </div>
</div>

Solution

  • In Your UL -> LI, add routerLink property and pass the movie id as the second param

    [routerLink]="['/movie/,x.movieId]">

    <ul>
       <li id="list-item" *ngFor="let x of movieResults; let i = index;" [routerLink]="['/movie/,x.movieId]">
        <img [src]="x.Poster" onerror="this.src='../assets/images/default-poster.jpg'">
        <p 
        id="movie-title" 
        class="is-size-5">{{x.Title}} ({{x.Year}}) </p>
      </li>
    </ul>