Tengo la siguiente configuración en Vue 3.
Una tienda vuex con una matriz como parte del estado:
const store = createStore({ state: { questions: [ { text: 'A', value: false }, { text: 'B', value: false }, { text: 'C', value: true }, ], }, mutations: { updateQuestionValue(state, { index, value }) { state.questions[index].value = value; }, }, });Y un componente que intenta generar una lista de casillas de verificación que deberían corresponder a la matriz de "preguntas" en el estado.
<template> <div v-for="(question, index) in questions"> <label :for="'q'+index">{{question.text}}</label> <input :id="'q'+index" v-model="questionComputeds[index]" type="checkbox" /> </div> </template> <script setup> import { computed } from 'vue'; import { useStore } from 'vuex'; const store = useStore(); const questions = computed(() => store.state.questions); const questionComputeds = store.state.questions.map((q, i) => computed({ get() { return store.state.questions[i].value; }, set(value) { store.commit('updateQuestionValue', { index: i, value }); }, }) ); </script> Como puede ver, espero usar v-model para promulgar un enlace bidireccional para cada elemento de entrada en la lista, pero como estoy usando vuex con una matriz, quiero usar la opción get/set en mis propiedades calculadas y acceso el específico calculado con un índice en la plantilla. Sin embargo, estoy encontrando que esto no funciona. No arroja un error, pero tampoco funciona para vincular el valor de la casilla de verificación a la propiedad .value en mis objetos de pregunta. ¿Estoy completamente equivocado sobre la táctica aquí? ¿Puedes incluso hacer arreglos de "computados", como yo con .map() ? ¿Alguna forma de usar v-model con esta estructura de datos?
En la primera línea de la plantilla.
<div v-for="(question, index) in questions">
questions no están definidas. Podría ser reemplazado por
<div v-for="(question, index) in questionComputeds">
o las questions pasadas a la tienda en la creación podrían extraerse a una variable, exportarse e importarse en su componente
A su segunda línea le falta un .value
Debiera ser
<input v-model="questionComputeds[index].value" type="checkbox" />
Estos dos cambios deberían solucionarlo. Teniendo en cuenta que no necesita el índice en la v, ya sea que obtenga el
<template> <div v-for="question in questionComputeds"> <input v-model="question.value" type="checkbox" /> </div> </template> <script setup> import { computed } from 'vue'; import { useStore } from 'vuex'; const store = useStore(); const questionComputeds = store.state.questions.map((q, i) => computed({ get: () => store.state.questions[i].value, set: (value) => { store.commit('updateQuestionValue', { index: i, value }) }, }) ); </script>Alternativas:
<template> <div v-for="(question, index) in questionComputeds"> <input :checked="questionComputeds[index]" type="checkbox" @input="handleChange(index, $event)" /> </div> </template> <script setup> import { computed } from 'vue'; import { useStore } from 'vuex'; const store = useStore(); const handleChange = (i, e) => { store.commit('updateQuestionValue', { index: i, value: e.target.checked }); // to verify: // console.log({ ...store.state.questions[i] }); } const questionComputeds = computed(() => store.state.questions.map(q => q.value)) </script> Extraiga su matriz de casillas de verificación a un componente separado y defina un v-model personalizado