I have been developing a Single Page Application using Vue 3, TypeScript, and the The Movie Database (TMDB) API.
In my src\components\MovieDetails.vue
file, I have implemented the following:
<template>
<div class="row">
<div class="col-sm-4 col-md-3">
<div class="poster-container text-center text-sm-start my-3">
<img v-if="movie"
:src="genericPoster"
:alt="movie?.title"
class="img-fluid shadow-sm"
/>
</div>
</div>
<div class="col-sm-8 col-md-9">
<h1 class="movie-title mt-4">{{ movie?.original_title }}</h1>
<p v-if="movie?.genres.length">
<strong class="pe-1">Genres:</strong>
<span
class="badge bg-secondary"
v-for="genre in movie?.genres"
:key="genre.id"
>{{ genre.name }}</span
>
</p>
<p v-if="movie?.vote_average" class="user-score">
<strong>User Score:</strong>
<span class="score" :class="movieQuality">{{
Number(movie?.vote_average).toFixed(2)
}}</span>
</p>
<div v-if="movie?.overview">
<h2 class="section-title">Overview</h2>
<p>{{ movie.overview }}</p>
</div>
<div v-if="movieTrailers.length" class="mb-3">
<h2 class="section-title">Trailers</h2>
<TrailerCarousel :movieTrailers="movieTrailers" />
</div>
<div v-if="movieCast.length" class="cast-container">
<h2 class="section-title">Cast</h2>
<div class="row">
<div
v-for="actor in movieCast.slice(0, 12)"
:key="actor['id']"
class="col-sm-3"
>
<ActorCard :actor="actor" />
</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { useRoute } from "vue-router";
import env from "../env";
import { Movie } from "@/models/Movie";
import { Trailer } from "@/models/Trailer";
import { MovieCast } from "@/models/MovieCast";
import TrailerCarousel from "./TrailerCarousel.vue";
import ActorCard from "./ActorCard.vue";
export default defineComponent({
name: "MovieDetails",
components: {
TrailerCarousel,
ActorCard,
},
data: () => ({
route: useRoute(),
genericPosterBig: require('../assets/generic-poster.png'),
movie: null as Movie | null,
movieQuality: String as unknown | 'bad',
movieCast: Array as unknown | MovieCast[],
movieTrailers: Array as unknown | Trailer[]
}),
mounted() {
this.getMovieDetails();
this.getMovieTrailers();
this.getMovieCast();
},
methods: {
getMovieDetails() {
this.$axios
.get(
`${env.api_url}/movie/${this.route.params.id}?api_key=${env.api_key}`
)
.then((response) => {
this.movie = response.data;
// Set the movie quality once it's retrieved
this.setMovieQuality();
})
.catch((err) => console.log(err));
},
setMovieQuality() {
if (Number(this.movie?.vote_average) >= 7) {
this.movieQuality = 'good';
} else if(Number(this.movie?.vote_average) < 7 && Number(this.movie?.vote_average) > 5.5) {
this.movieQuality = 'average';
} else {
this.movieQuality = 'bad';
}
},
getMovieTrailers() {
this.$axios
.get(
`${env.api_url}/movie/${this.route.params.id}/videos?api_key=${env.api_key}`
)
.then((response) => {
this.movieTrailers = response.data.results;
})
.catch((err) => console.log(err));
},
getMovieCast() {
this.$axios
.get(
`${env.api_url}/movie/${this.route.params.id}/credits?api_key=${env.api_key}`
)
.then((response) => {
this.movieCast = response.data.cast;
})
.catch((err) => console.log(err));
},
},
computed: {
genericPoster() {
return !this.movie?.poster_path
? this.genericPosterBig
: `https://image.tmdb.org/t/p/w500/${this.movie?.poster_path}`;
},
},
watch: {
"$route.params.id"() {
this.getMovieDetails();
this.getMovieTrailers();
this.getMovieCast();
},
},
});
</script>
In the src\models\MovieCast.ts
file:
export interface MovieCast {
adult?: boolean;
character?: string;
name?: string;
profile_path?: string;
}
Instead of the previous lines in the components:
movieCast: Array as unknown | MovieCast[]
movieTrailers: Array as unknown | Trailer[]
I initially had:
movieTrailers: [],
movieCast: [],
I decided to make this change to ensure a more strictly typed application.
The Issue
However, after making this update, the console error displayed is:
TypeError: _ctx.movieCast.slice is not a function
<div
v-for="actor in movieCast.slice(0, 12)"
:key="actor['id']"
class="col-sm-3"
>
<ActorCard :actor="actor" />
</div>
A working demonstration of the app can also be found on Stackblitz.
Queries
- What could be the mistake I am making?
- What would be the most effective way to resolve this issue?