Reputation: 76
I am new to Vue js so sorry for the stupid question. I am using a v-data-table to loop through an array. I need the return from a method to not change, but when the method runs it changes for every row.
I have tried a computed value but for some reason you can't pass a variable into a computed field?
<template>
<div>
<v-data-table
:items="responseData"
class="elevation-1"
>
<template slot="items" slot-scope="props">
<td :key="props.item.tmdbId" class="text-xs-right">
This: {{checkMovieExists(props.item.tmdbId)}}
</td>
</template>
</v-data-table>
</div>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
allMovies: []
};
},
mounted() {
axios.get("XXXX")
.then(response => (this.allMovies = response.data))
},
methods: {
checkMovieExists(strMovieTmdbId){
this.allMovies.forEach(movie => {
if (movie.tmdbId == strMovieTmdbId) {
return "Exists"
}
});
}
}
}
</script>
Upvotes: 0
Views: 1212
Reputation: 20737
Computed properties are calculated based on the internal state only. They are special in the sense that they only have to be recalculated whenever the internal state on which they depend is changed. They don't accept any arguments, because that would make them rely on more than reactivity of your state, which defeats this caching mechanism. You could use a computed property to process the data you got from the api and loop over that instead, but lets ignore that for now.
As pointed out in the comments, the problem with your method is that you are using a forEach
loop with a function, and return in the inner function. The outer function does not return anything, and thus the return value is undefined
. There are several ways you can do this, but I think using Array.prototype.some
works best in your case. You pass this method a function which is executed for each item in the array you are invoking it on. The entire thing returns true
if any of these invocations returns true
, and otherwise it returns false
.
movieExists(strMovieTmdbId){
return this.allMovies.some(movie => movie.tmdbId === strMovieTmdbId);
}
You will notice that I return a boolean here. I do this because your function is called XYZExists
. We can use this boolean response to output something appropriate in the template.
<template slot="items" slot-scope="props">
<td :key="props.item.tmdbId" class="text-xs-right">
This: {{ checkMovieExists(props.item.tmdbId) ? 'Exists' : '' }}
</td>
</template>
As far as the use of scoped slots goes, I believe you are doing it mostly correct as long as this.allMovies
is something like:
[
{
tmdbId: 1
},
{
tmdbId: 2
}
]
Keep in mind that the items
slot renders an entire row, not just one cell. You will need to surround it with <tr> ... </tr>
.
As thanksd commented below, using this method may cause performance issues if the template is rerendered a lot. After all, each time the method is invoked, it looks through an entire array, for every item in that array.
Instead we can prepare the data using a computed property. Since you only assign data once in the mounted hook, your computed property should only be calculated once. Of course, you should then avoid mutating this.allMovies
to prevent recalculation of your computed property.
You can keep the method we created earlier, but instead of using this.allMovies
to render the data, we are going to use this method to calculate the data... once. We use a map to create an extra property that contains the result of the method.
computed: {
preparedData () {
return this.responseData.map(
row => {
return {
...row,
exists: this.movieExists(row.tmdbId)
}
}
);
}
}
Now, instead of using responseData
(whatever that is), we use preparedData
to render the table. Since we now have a precalculated property exists
on each row, we can just check props.item.exists
instead of having to invoke a function. When the template is rerendered, as long as responseData
stays constant, we use the cached version of preparedData
.
<v-data-table
:items="preparedData"
class="elevation-1"
>
<template slot="items" slot-scope="props">
<td :key="props.item.tmdbId" class="text-xs-right">
This: {{ props.item.exists ? 'Exists' : '' }}
</td>
</template>
</v-data-table>
Upvotes: 2