Create an array of dynamically calculated properties from the Vuex state array, which can then be utilized in the v-model

In my Vue 3 setup, I have a Vuex store with an array in the state:

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;
    },
  },
});

I also have a component that is supposed to display a list of checkboxes corresponding to the "questions" array in the state.

<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>

While trying to achieve two-way binding using v-model for each input element in the list, it seems that accessing specific computeds with an index in the template is not working as expected. Although there are no errors thrown, the binding between the checkbox value and the .value property in the question objects is not functioning correctly. Is my approach incorrect here? Can arrays of "computed" properties be created using .map()? Is there any way to utilize v-model with this particular data structure?

Answer №1

issue number one:

The problem lies in the initial template line

<div v-for="(question, index) in questions">

The variable questions is not defined. You can solve this by using

<div v-for="(question, index) in questionComputeds">

Alternatively, you can extract the questions passed to the store during creation, export it, and import it into your component

issue number two:

Your second line is missing a .value

It should be:

<input v-model="questionComputeds[index].value" type="checkbox" />

By making these adjustments, your code should work correctly. Additionally, if you don't need the index in the v-for loop, consider the following simplified solution:

solution:
<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>

Other options include:

easy fix:
<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 });
  // for verification:
  // console.log({ ...store.state.questions[i] });
}

const questionComputeds = computed(() => store.state.questions.map(q => q.value))

</script>
advanced solution for reusability:

If needed, separate your checkbox array into its own component and define a custom v-model

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Invoke the method in customButton component of fullcalendar

I've integrated a custom button into my fullcalendar: ngOnInit() { this.calendarOptions = { customButtons: { custom1: { text: 'Add event', click() { this.openModal(); } } }, height: 600, editable: t ...

What are the steps to crawl and save content from multiple websites simultaneously?

My project involves creating a webpage that can crawl multiple other webpages and integrate the data. I am using node.js & vue.js for this purpose. By utilizing puppeteer & cheerio, I have successfully been able to crawl a single page and store its data i ...

Deactivating attribute inheritance / configuring component settings with script setup and Typescript

Is there a way to disable attribute inheritance for a component's options when using script setup syntax with Typescript in Vue 3? Here is the JavaScript code example: app.component('date-picker', { inheritAttrs: false, // [..] }) How ...

Once an ng-repeat is completed, I must extract and retrieve the 'id' of a specific element

Is it possible to retrieve the 'id' of the comment I'm replying to and save it for an Ajax call? I can easily access other data with ng-model, but using value="{{this.id}}" in a hidden input doesn't seem to work like in JQuery. <scr ...

I'm trying to create a transparent v-card, but for some reason it's not turning out the way I want

How can I make the v-card transparent while keeping its content opaque using CSS? card.vue <v-card class="cardColor"> <v-card-text> TEXT </v-card-text> <v-card-actions> <v-btn color="prima ...

Activate a function in Jquery after iterating through all elements in a JSON file

Below is the code I am using to ping a list of computers with Jquery and asp.net. function ping() { $('#progress').css("display", ""); $('.comp').each(function () { var $computer = $ ...

Retrieve the post ID from the existing URL via AJAX in order to fetch data associated with that particular ID

Currently, I am facing an issue while trying to pass the id from the current URL to the select.php page. The error displayed is 'id not defined' and as a result, no data is being fetched. My goal is to retrieve data for the suporder index from th ...

Guide on toggling visibility of a column in Material-ui based on a conditional statement

Can someone help me with code that allows me to hide or show the TableCell based on an if statement? I am currently working with MATERIAL-UI framework which can be found here: https://material-ui.com/ <TableBody> {Object.entries(servicesCode).map ...

Images appear as plain text in the preview of VUE 3 (with TypeScript)

Currently, I am developing a Portfolio website and have encountered an issue. While everything runs smoothly with npm run dev, the problem arises when I use npm run preview. In this scenario, some of the images within the files named 3dModellingFiles.ts do ...

Guiding you on exporting a Typescript class with parameters in Node.js

Trying to find the Typescript equivalent of require('mytypescriptfile')(optionsObject); This is the TS code provided: export class Animal { name: string; public bark(): string { return "bark " + this.name; } constructor(color:string) ...

Is it considered safe to display the error message from an AJAX call for security reasons?

When I make my ajax calls, they usually follow this pattern: $.ajax({ type: 'POST', url: '/Controller/DoSomethingSpecial', contentType: 'application/json;', ...

Making sure that the height of the <section> element is equal to the height of the viewport when the page

Is there a way to dynamically adjust the height of a <section> element to match the viewport every time the page is reloaded? Once the height is set, it should remain fixed even if the user resizes the window. For example, if the viewport's hei ...

Deactivate DropDownList within Update Panel with JQuery

Below is the Update Panel that I am working on: <asp:ScriptManager ID="ScriptManager1" runat="server" /> <asp:UpdatePanel ID="UpdatePanel1" UpdateMode="Conditional" runat="server"> <Triggers> <asp:AsyncPostBackTrigger ControlID="d ...

Having trouble with the clip-path in d3.js liquid fill gauge

Attempting to integrate the d3.js liquid fill gauge into my angular2 webapp has been a challenge. The clippath functionality seems to be malfunctioning, resulting in no wave being generated at all. https://i.stack.imgur.com/3Bmga.png instead of https://i. ...

Searching for getStaticPaths using a GROQ query that involves nested dynamic routing

My NextJS project has a complex nested folder structure. You can view the layout here. Utilizing Sanity as my CMS, the getStaticPaths function within my index.js file is functioning properly: export const getStaticPaths = async () => { const routes ...

Can images be placed on the border?

Hi there! I am trying to add an image on a border with a 100px solid width using CSS. I have experimented with positions and z-index, but I can't seem to get the desired effect. Any ideas on how to achieve this? Here is an example image: https://i.sst ...

Live AJAX inquiries in progress

Is there a way to track the number of active AJAX requests in jQuery, Mootools, or another library similar to Prototype's Ajax.activeRequestCount? I am looking for a method that can be used across different libraries or directly through XMLHttpRequest ...

Tips for automatically resizing a canvas to fit the content within a scrollable container?

I have integrated PDF JS into my Vue3 project to overlay a <canvas id="draw_canvas"> on the rendered pdf document. This allows me to draw rectangles programmatically over the pdf, serving as markers for specific areas. The rendering proces ...

Can someone provide guidance on how to validate a HEX color in Cypress?

As I dive into testing with Cypress, my lack of experience has become apparent. I am trying to test the background-color CSS property on a specific element, but running into an issue - everything is in RGB format behind the scenes, while I need to work wit ...

Having trouble integrating a custom plugin with CKEditor?

I am currently using version 4.7 of CKEditor, which is the latest version available. I am facing an issue where I cannot see a new custom plugin that I have added to the toolbar. I have checked my basic example of abbreviation (abbr) plugin but couldn&apos ...