Vue 3: How to respond to changes in an object property within an array

I have a Vue 3 application. Within this app, I am aiming to showcase a list of items and provide users with the ability to choose items within the array. The current structure of my component is outlined below:

MyComponent.vue

<template>
  <div>
    <div v-for="(item, index) in getItems()" :key="`item-${itemIndex}`">
      <div class="form-check">
        <input class="form-check-input" :id="`checkbox-${itemIndex}`" v-model="item.selected" />
        <label class="form-check-label" :for="`checkbox-${itemIndex}`">{{ item.name }} (selected: {{ item.selected }})</label>
      </div>
    </div>

    <button class="btn" @click="generateItems">Generate Items</button>
  </div>
</template>

<script>
  import { reactive } from 'vue';

  export default {
    data() {
      return itemCount: 0
    },

    methods: {
      generateItems() {
        this.itemCount = Math.floor(Math.random() * 25) + 1;
      },

      getItems() {
        let items = reactive([]);
        for (let i=0; i<this.itemCount; i++) {
          items.push({
            id: (i+1),
            selected: false,
            name: `Item #${i+1}`
          });
        }
        return items; 
      }
    }
  }
</script>

When trying to select/deselect the checkbox, the text displaying whether it is "selected" or not does not update accordingly. This indicates that there might be an issue with how I am binding the property. At this point, I could use some guidance on what might be going wrong.

Is there a specific way to bind a checkbox to an object property within an Array in Vue 3?

Answer №1

By adding a breakpoint in the getItems() function or inserting a console.log statement within it, you may observe that each time a checkbox selection is modified, the function is triggered. This behavior occurs because the v-for loop undergoes re-rendering, causing getItems() to be called and return a new list of items with all selected values reset to false. The previous data is then no longer utilized by any part of the application.

A potential solution would be to limit calling the getItems() function only within generateItems(), storing the resulting array in a designated location such as the data object. Subsequently, adjust the v-for directive to iterate over this stored array rather than directly invoking the getItems() method.

Answer №2

Steve was spot-on.

Here is the corrected version: Check out Vue SFC Playground.

<template>
  <div>
    <div v-for="(item, index) in items" :key="`item-${index}`">
      <div class="form-check">
        <input type="checkbox" class="form-check-input" :id="`checkbox-${index}`" v-model="item.selected" />
        <label class="form-check-label" :for="`checkbox-${index}`">{{ item.name }} (selected: {{ item.selected }})</label>
      </div>
    </div>

    <button class="btn" @click="generateItems">Generate Items</button>
  </div>
</template>

<script>
  import { reactive } from 'vue';

  export default {
    data() {
      return { items: [] }
    },
    methods: {
      generateItems() {
        this.itemCount = Math.floor(Math.random() * 25) + 1;
        this.getRndItems();
      },
      getRndItems() {
        this.items = reactive([]);
        for (let i=0; i<this.itemCount; i++) {
          this.items.push({
            id: (i+1),
            selected: false,
            name: `Item #${i+1}`
          });
        }
      }      
    }
  }
</script>

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

Creating test doubles using Sinon allows you to effectively block the execution of the original function

I am currently engaged in JavaScript unit testing using Mocha and Sinon. My goal is to verify if a specific method is called under certain conditions. However, I have encountered difficulties purely testing the method call. To clarify, I aim to replace th ...

Attempting to prevent altering a property nested three levels deep without using mutation, utilizing $emit instead

EDIT: Check out this repository that I created for easier parsing. I have developed a Component that displays products in a datatable. The first column of the table contains a link that triggers a modal displaying a form specific to the product that was c ...

Ways to differentiate between a desktop browser width of 1024px and a tablet width of 1024px with the help of jquery

So here's the issue I'm dealing with: I have scroll-based animation functions set up for desktop browsers, and different animations in place for tablet browsers. The challenge is to make these functions work on a desktop with a 1024px dimension. ...

Footer Cell isn't showing up as expected within *ngFor loop in Mat-Table

I'm having trouble displaying the total sum at the bottom of my table. Despite following the steps outlined in the documentation exactly, it still doesn't seem to be working for me. Below you can find the code from my template: <table mat-t ...

Change the name of the public directory to public_html within the Laravel framework

In my current project, I am utilizing Laravel along with Vuejs. As part of the project setup, I decided to rename the public folder to public_html. However, a recurring issue arises when running the "npm run watch" command, as it ends up recreating the pub ...

Troubleshooting: Issue with AJAX xmlhttp.send() functionality

I'm new to AJAX and have been stuck on the same issue for hours. Here is my script code: <script language='javascript'> function upvote(id ,username) { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = fun ...

What steps do I need to take to create a calendar with this appearance?

I am working on my college project website and I would like to display a calendar similar to this. How can I achieve this using CSS and JavaScript? I want the user to be able to hover over a date to see all dates of the month, as well as have options to se ...

Deactivate the button when an item is selected from the dropdown menu in JavaScript

I am working on a dropdown menu containing values that link to functions, along with a textbox and submit button. My goal is to have the submit button disabled or hidden when a specific value is selected from the dropdown, possibly alongside clearing the c ...

An error occurs when attempting to access data from the JSON file

Currently, I am utilizing an API to retrieve the balance from a bitcoin address. This is my code: async function getWalletBalance(address) { try { const response = await got(`blockchain.info/balance?active=${address}`) return response ...

Is there a way to combine JavaScript, CSS, and HTML code in a single HTML document?

Is there a way to include both <script> and <style> elements within the same HTML body? <html> <head> <title>My site title</title> </head> <body> </body> </html> I am looking to in ...

Elevate the value within a function and refresh the said function

I'm currently facing a challenge with this particular piece of code, let spin = new TimelineMax(); spin.to($('.particle'), 150, { rotation: 360, repeat: -1, transformOrigin: '50% 50%', ease: Linear.easeNone }); Th ...

Component not being updated by Vuex

I am currently working on a website using Vue and Vuex with TypeScript. (Apologies for the lengthy code samples) Within my project, I have a Store Module called 'musicArtists': const actions: ActionTree<MusicArtist[], any> = { getAllA ...

What is the reason for function expressions being hoisted when called within Express JS middleware?

It's common knowledge that function declarations are hoisted, allowing them to be called from anywhere in your script. However, this is not the case for function expressions. For instance: test(); const test = () => { console.log(1+3); } ...

Is it possible to retrieve the createdAt timestamp without displaying the 'GMT+0000 (Coordinated Universal Time)'?

After conducting an extensive search, I have yet to find a satisfactory answer. My goal is to configure it without including the CUT time. {name: "Registered:", value: `${user.createdAt}`}, {name: "Joined:", value: `${message.guild.joinedAt}`} Presently, ...

Utilize React HOC (Higher Order Component) and Redux to retrieve data and pass it as props

In my quest to develop a Higher Order Component (HOC) that can execute methods to fetch data from the backend and display a loader mask during loading, I encountered a challenge. I aim to have the flexibility of passing different actions for various compon ...

in AngularJS, check for object attributes existence before proceeding to use them

Currently, I have a filter function that is designed to check the latitude and longitude distance of objects within an array against the range selected by the user. However, there is a problem in which some objects within the array do not possess latitude ...

Using Laravel, how can I retrieve the specific user ID associated with an element?

I am seeking a solution to retrieve the User ID from the users table using either JavaScript or Laravel. But why do I need it? The reason is that I want to populate a modal window popup with specific user information. I currently have 10 users, each with ...

How can I simulate a side plugin for Vue component testing?

I am currently using Vue 2 along with vue-test-utils and jest for testing. One of the plugins I use is vue-croppa, which allows me to upload pictures. import Croppa from 'vue-croppa' Vue.use(Croppa, { componentName: 'image-croppa' }) ...

Vue js: Automatically assign alternate text to images that are not found

Currently, I am in the process of developing a website that features a variety of products, each with its own unique image. For binding the image URL to the source attribute, I use the following code snippet: <img :src="product.ImageUrl"/> In case ...

Tips for implementing the .nex() property from jQuery in CSS styling

When I add the class "playing", then I will apply custom CSS to the next li tag. Please review my code and see if you understand. Please take a look at my code. <ul> <li class="playing">li (sibling)</li> <li id="head">li ...