I am trying to create a v-for that shows a list of exercises containing several sets. I have created a loop with a row for each set underneath each exercise.
my data looks like this.
const exercises = [
{ id: 1, name: exercise1, sets: 3 },
{ id:2, name: exercise2, sets: 2 }
{ id:3, name: exercise3, sets: 4 }
]
And my component looks something like this:
<template v-for="exercise in exercises" :key="exercise.id">
<span> {{ exercise.name }} </span>
<template v-for="set in exercise.sets" :key="set">
<span @click="completeSet()"> {{ set }} </span>
</template>
</template>
Now I want to be able to mark each set as completed by setting the value on each set to either true or false through a click event. But I am not sure about how to do this since each set doesn't have a property to set a value because it's looping through a number.
What would be the right approach to this problem?
CodePudding user response:
First and foremost, you can't loop through a number. To be able to loop the sets, you'd have to
<template v-for="let set = 0; set < exercise.sets; set " :key="set">
<span @click="completeSet()"> {{ set }} </span>
</template>
However, setting a property on a number is equally impossible. You have to prepare your data to be able to make that adjustment:
const exercises = [
{ id: 1, name: 'exercise1', sets: 3 },
{ id: 2, name: 'exercise2', sets: 2 } ,
{ id: 3, name: 'exercise3', sets: 4 }
].map(exercise => ({
id: exercise.id,
name: exercise.name,
sets: Array.from(
{ length: exercise.sets },
() => ({ completed: false })
),
}))
CodePudding user response:
You can create array with finished sets and compare it (try the snippet pls):
new Vue({
el: "#demo",
data() {
return {
exercises: [{ id: 1, name: 'exercise1', sets: 3 }, { id: 2, name: 'exercise2', sets: 2 }, { id: 3, name: 'exercise3', sets: 4 }],
finishedSets: []
}
},
methods: {
compareObjects(o1, o2) {
return Object.entries(o1).sort().toString() !== Object.entries(o2).sort().toString()
},
findObject(id, set) {
return this.finishedSets.find(f => f.id === id && f.set === set)
},
completeSet(id, set) {
this.findObject(id, set) ?
this.finishedSets = this.finishedSets.filter(f => {return this.compareObjects(f, this.findObject(id, set))}) :
this.finishedSets.push({id, set})
},
isFinished(id, set) {
return this.findObject(id, set) ? true : false
}
}
})
.set {
width: 70px;
cursor: pointer;
}
.finished {
background-color: seagreen;
}
.finished__not {
background-color: tomato;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div v-for="exercise in exercises" :key="exercise.id">
<span> {{ exercise.name }} </span>
<div v-for="set in exercise.sets" :key="set">
<div @click="completeSet(exercise.id, set)" :> {{ set }} <span>
<span v-if="isFinished(exercise.id, set)">finished</div>
</div>
</div>
{{finishedSets}}
</div>