Building an SPA using Vue 3, TypeScript, and The Movie Database (TMDB) API has been my latest project. In order to differentiate the movie score "bubble" with different styles, I have utilized the computed property movieQuality
.
To achieve this, within src\components\MovieDetails.vue
, I have included:
<template>
<div class="row">
<div class="col-sm-4 col-md-3">
<div class="poster-container text-center text-sm-start my-3">
<img
:src="`https://image.tmdb.org/t/p/w600_and_h900_bestv2/${movie.poster_path}`"
:alt="movie.title"
class="img-fluid shadow-sm"
/>
</div>
<div class="user-score">
<strong>User Score:</strong>
<span class="score" :class="{ good: isGood, average: isAverage , bad: isBad }">{{
Number(movie.vote_average).toFixed(2)
}}</span>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { useRoute } from "vue-router";
import axios from "axios";
import env from "../env";
import TrailerCarousel from "./TrailerCarousel.vue";
import ActorCard from "./ActorCard.vue";
export default defineComponent({
name: "MovieDetails",
components: {
TrailerCarousel,
ActorCard,
},
data() {
return {
route: useRoute(),
movie: Object,
movieTrailers: [],
movieCast: [],
};
},
mounted() {
this.getMovieDetails();
},
methods: {
getMovieDetails() {
axios
.get(
`${env.api_url}/movie/${this.route.params.id}?api_key=${env.api_key}`
)
.then((response) => {
this.movie = response.data;
})
.catch((err) => console.log(err));
},
// More code, not relevant to the question
computed: {
movieQuality() {
switch(true) {
case Number(this.movie.vote_average) <= 6:
return 'bad'
break;
case Number(this.movie.vote_average) > 6 && Number(this.movie.vote_average) < 7.5:
return 'average'
break;
default:
return 'good'
}
}
}
});
</script>
<style scoped lang="scss">
.user-score {
display: flex;
align-items: center;
.score {
width: 30px;
height: 30px;
margin-left: 5px;
border-radius: 50%;
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.1);
font-size: 11px;
line-height: 1;
font-weight: 500;
display: flex;
justify-content: center;
align-items: center;
&.good {
background: #0b8a52;
color: #fff;
}
&.average {
background: #f7ff1d;
color: #222;
}
&.bad {
background: #ff1d30;
color: #fff;
}
}
}
</style>
Latest Update
A new "model" has been created in src\models\Movie.ts
:
export class Movie {
id?: number;
adult?: boolean;
backdrop_path?: string;
poster_path?: string;
title?: string;
tagline?: string;
overview?: string;
genres?: any;
original_title?: string;
release_date?: string;
runtime?: number;
vote_average?: string;
}
It is imported into the component like so:
import { Movie } from "../models/Movie";
and implemented as follows:
data() {
return {
route: useRoute(),
movie: Movie, // Utilizing the model now
movieTrailers: [],
movieCast: [],
};
},
Stackblitz Demo
A live demo of the project can be accessed on Stackblitz via HERE.
The Issue at Hand
Despite Evan believing that the vote_average
property exists within the movie
object, the movieQuality()
function throws an error:
Property 'vote_average' does not exist on type 'ObjectConstructor'.
Queries
- In what way am I overlooking things?
- What is the most effective approach to rectify this concern?