The Vue.js class bound to the object remains static even after the object is updated

When I have a number of buttons, generated using the v-for directive, with each button having an initial class based on a string from an object. There is an event that changes this string when a button is clicked. However, the class does not get updated along with the string change. What could be the issue here?

<template>
    <v-layout>
        <v-btn v-for="cell in cells" :key='cell.id' v-bind:class='cell.color' 
            v-on:click='click(cell.id)'>
            <p v-if="cell.win">win</p>
            <p>{{cell.id}}</p>
        </v-btn>
    </v-layout>
</template>

<script>

export default {
    data() {
        return {
            cells: {

            },
            winId: 0,
        }
    },
    methods: {
        generateCells() {
            this.winId = Math.floor(Math.random() * 100);
            for (var i = 0; i < 100; i++) {
                this.cells[i] = {
                    id: i,
                    color: 'info'
                }
            }
        },
        click(id) {

            if (this.cells[id].id === this.winId) {
                alert('You win');
                this.cells[id].color = 'success';
            } else {
                this.cells[id].color = 'warning';
            }
        }
    },
    created() {
        this.generateCells();
    }
}

</script>

I am anticipating that the button class will be updated whenever the respective object is updated. Although the .color property of the object gets updated, the class itself remains unchanged.

Answer №1

Due to the constraints of modern JavaScript (and the discontinuation of Object.observe), Vue is unable to recognize property additions or deletions. In Vue, the conversion of getters/setters occurs during instance initialization, so a property needs to be present in the data object for Vue to convert it and make it reactive.

For more information, check out: Reactivity in Depth.

Vue offers an API to add properties to nested objects at different levels and make them reactive.

To achieve this, you can utilize:

Vue.set(object, propertyName, value);

You can also employ the vm.$set method like this:

this.$set(this.someObject, 'b', 2);

In your code snippet, when setting the value of an array, you need to do the following:

this.$set(this.cells, i, {
                           id: i,
                           color: 'info'
                         });

Refer to the complete example below:

window.onload = () => {
  new Vue({
    el: '#app',
    data: () => {
      return {
        cells: {

        },
        winId: 0,
      }
    },
    methods: {
      generateCells() {
        this.winId = Math.floor(Math.random() * 100);
        for (var i = 0; i < 100; i++) {
          this.$set(this.cells, i, {
            id: i,
            color: 'info'
          })
        }
      },
      click(id) {
        if (this.cells[id] == this.winId) {
          alert('you win');
          this.cells[id].color = 'success';
        } else {
          this.cells[id].color = 'warning';
        }
      }
    },
    created() {
      this.generateCells();
    }
  })
}
body {
  padding: 1rem;
}

.info {
  color: blue;
}

.warning {
  color: red;
}

.success {
  color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <v-layout>
    <v-btn v-for="cell in cells" :key='cell.id' v-bind:class='cell.color' v-on:click='click(cell.id)'>
      <p v-if="cell.win">win</p>
      <p>{{cell.id}}</p>
    </v-btn>
  </v-layout>
</div>

Answer №2

To delve deeper into the intricacies of data and methods, refer to the Vue documentation.

It's important to keep in mind that properties in data will only reactively update if they were present when the instance was first created. This means that adding a new property like:

vm.b = 'hi'

will not trigger any view updates when changes are made to b.

If you find yourself needing to set prop values within a loop, consider using Vue.set() or this.$set() API.

Alternatively, you can replace the entire object as shown below:

var cells = {}
for (var i = 0; i < 100; i++) {
    cells[i] = {
    id: i,
    color: 'info'
    }
}
this.cells = cells

Afterwards, in a click callback function:

var newCell = {}
if (this.cells[id] == this.winId) {
    alert('you win');
    newCell[id] = {id:id,color:'success'}
} else {
    newCell[id] = {id:id,color:'warning'}
}
this.cells = Object.assign({},this.cells,newCell)

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

What is the best way to fill an array within an object using React Hooks?

I am encountering an issue with an object that includes an array. Here is the code snippet in question: const [data, setData] = useState({ jobs: [] }); Currently, I am retrieving data from an API and need to append this fetched information to the jobs arr ...

The AJAX request encountered an error while trying to send a POST request to the http://localhost/upload/undefined endpoint. The

I've been scouring the internet and testing for hours, but I'm still unable to identify the source of the error. I could really use some assistance here. I meticulously followed a tutorial on multiple file uploads with drag & drop functionali ...

What are some more efficient methods for implementing page location detection with Angular directives?

My website currently features a navigation bar with 4 anchor links that direct users to different sections of the page. As you scroll down the page, the corresponding link on the nav bar lights up to signify your position on the site. Experience it yourse ...

Is SWR failing to provide outdated data?

My understanding was that SWR should display the cached data upon page load before refreshing with new information from the API. However, in my Next.js app with a simple API timeout, the "loading" message appears every time due to the 5-second delay I adde ...

Encountering an issue when trying to download a PDF from an Angular 6 frontend using a Spring Boot API - receiving an error related to

When I directly call the Spring Boot API in the browser, it successfully creates and downloads a PDF report. However, when I try to make the same GET request from Angular 6, I encounter the following error: Here is the code snippet for the Spring Boot (Ja ...

I am able to access the JSON file from the URL without any issues, but for some reason, I am unable to fetch it using $

(function(){ $(document).ready(function(){ $.getJSON('http://dev.markitondemand.com/MODApis/Api/v2/Quote/json?symbol=AAPL&callback=?', function(){console.log("function was run");}); }); }()) I recently delved into working with APIs. Ho ...

Oops, it seems like there is a TypeError with the function window.initMap in Google Maps

For the past week, I have been struggling to update my marks on Google Maps while using AJAX in an HTML page. My controller fetches data from the database and sends it back, but now I am encountering the following error: TypeError: window.initMap is not a ...

Issue: Module "expose?Zone!zone.js" could not be located

Just started experimenting with Angular 2 and encountering an issue when importing zone.js as a global variable: https://i.stack.imgur.com/gUFGn.png List of my packages along with their versions: "dependencies": { "angular2": "2.0.0-beta.3", "es ...

Utilizing Jquery to enhance table filtering functionality

I created a table listing various places, along with buttons to filter the list. The first filter is based on location (north, east, central, south, west) determined by postcode. The other filter is for "impress" which only displays places with a rating of ...

Understanding how Vue CLI v3 determines which JavaScript files should be separated into different chunks

Struggling to grasp the new CLI and configuration adjustments. The official documentation lacks details on incorporating CSS as an entry point instead of directly importing it into a component or main.js. Noticing that some JS files are being split into s ...

Handling an HTML Form without the Submit Button using VeeValidate

I've implemented a form handler using its composable feature in my <script setup>: const { submitForm, resetForm, handleSubmit, meta } = useForm() function save() { // Want to submit the form here submitForm() // Not working showSaveSnac ...

Determine whether a directive possesses a specific attribute

Here is my current code snippet: <my-directive></my-directive> I am trying to include a ternary operation within it like this: {{ $scope.my-option ? 'YES' : 'NO' }} Is it possible to achieve the desired result by adding ...

Navigating JSON Data in Groovy Using a Loop: A Handy Guide

Just starting out with Groovy and attempting to mock a service in SoapUI. The task at hand involves loading a text file containing JSON data, and then matching that data to a specific node. Here is what I have attempted so far: def inputFile = new File( ...

Removing the Login button from the layout page after the user has logged in can be achieved by

I am currently developing an MVC application in Visual Studio 2012. Within my layout page, there is a login button that I would like to hide after the user successfully logs in. Despite my attempts, the method I am using doesn't seem to be working. Ca ...

Is it possible to create floating unordered lists using Bootstrap in HTML?

Is there a way to float text left or maintain list order in the HTML code of my page while using a dense CSS from this bootstrap template? For example, I would like my list to remain organized regardless of how many items are added: However, after adding ...

The navigation functionality in vue.js is experiencing issues with the router integration

As I work on securing my routers in vue.js, I have implemented user authentication to restrict access to unauthorized users. However, I encountered a loophole where a logged-in patient could access the profile of a doctor by navigating to the respective ro ...

Prevent form submission when processing is in progress

I've got this code working perfectly: $(function() { $("input,textarea").jqBootstrapValidation({ preventSubmit: true, submitError: function($form, event, errors) { // additional error messages or events ...

CSS Element Overlapping Issue in Safari Browser

I am currently developing an audio player for my application that includes a pause/play button, next button, and back button. I have encountered a problem specifically on Safari where the back/pause buttons are overlapping each other. The play/pause button ...

Issue with Angular controller failing to load when link is clicked

I am currently developing a webpage that incorporates Angular and responds to ajax requests by populating data into a table. When I manually enter the address, everything works as expected. However, if I navigate to the page using a link ( <a href="/pro ...

A more detailed explanation of Angular's dot notation

I came across a solution for polling data using AngularJS here on stackoverflow. In this particular solution (shown below), a javascript object is used to return the response (data.response). I tried replacing the data object with a simple javascript arra ...