Estoy tratando de crear un v-for que muestre una lista de ejercicios que contengan varios conjuntos. He creado un bucle con una fila para cada serie debajo de cada ejercicio.
mis datos se ven así.
const exercises = [ { id: 1, name: exercise1, sets: 3 }, { id:2, name: exercise2, sets: 2 } { id:3, name: exercise3, sets: 4 } ]Y mi componente se parece a esto:
<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>Ahora quiero poder marcar cada conjunto como completado estableciendo el valor de cada conjunto en verdadero o falso a través de un evento de clic. Pero no estoy seguro de cómo hacer esto, ya que cada conjunto no tiene una propiedad para establecer un valor porque está recorriendo un número.
¿Cuál sería el enfoque correcto para este problema?
En primer lugar, no puede recorrer un número. Para poder enlazar los conjuntos, tendrías que
<template v-for="let set = 0; set < exercise.sets; set++" :key="set"> <span @click="completeSet()"> {{ set }} </span> </template>Sin embargo, establecer una propiedad en un número es igualmente imposible. Tienes que preparar tus datos para poder hacer ese ajuste:
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 }) ), }))Puede crear una matriz con conjuntos terminados y compararla (pruebe el fragmento por favor):
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: [] } }, computed: { checkAll() { return this.exercises.reduce((acc, curr) => acc + curr.sets, 0) === this.finishedSets.length } }, 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)" class="set" :class="isFinished(exercise.id, set) ? 'finished' : 'finished__not'"> {{ set }} <span> <span v-if="isFinished(exercise.id, set)">finished</div> </div> </div> <button v-if="checkAll">submit</button> <p>{{finishedSets}}</p> </div>