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 duration that browsers retain downloaded assets during a single session?

Is it necessary to preload data from the server in order to have immediate access when needed? The data is stored in a file named "data.json". Initially, I considered storing data.json in an object and referencing it whenever required. However, given tha ...

What is the best way to add the current date to a database?

code: <?php session_start(); if(isset($_POST['enq'])) { extract($_POST); $query = mysqli_query($link, "SELECT * FROM enquires2 WHERE email = '".$email. "'"); if(mysqli_num_rows($query) > 0) { echo '<script&g ...

Await the reply from Angular while using Selenium WebDriver

I am currently automating an Angular-based application using Selenium WebDriver (Java). After selecting an option from a dropdown in the Application Under Test (AUT), data is loaded onto the page through an AJAX call to a web service. However, there is no ...

Step-by-step guide on eliminating the modal post-validation

Newbie in reactjs looking for help with modal validation issue. Goal: Press submit button inside modal, validate, then close the modal. Want to reuse modal for another row. Problem: I'm having trouble making the function work for a new row after ...

Tips for enabling auto-scroll feature in MuiList

Currently, I am working on a chat window component that utilizes Material UI for styling. I expected that setting a height or max-height on either the MuiList or MuiBox encapsulating the list would automatically scroll to the new message when it's sen ...

Conceal the legend in Highcharts using Python script with Django

Need some assistance with a Django and Highcharts.js project I'm working on. Objective: hide the legend in a Highcharts chart from my views.py script. In my views.py file, I've successfully plotted various charts but struggling to hide the lege ...

Tips for preventing Chrome from masking the background image and color on an autofill input

Google Chrome Browser has caused the background-color and background-image effects to be removed from the Username and Password input fields. Before autocomplete https://i.stack.imgur.com/Ww7Hg.png After autocomplete https://i.stack.imgur.com/hbG2C.png ...

What could be causing me to receive null when trying to retrieve an element with document.getElementById, even after invoking $(document).ready(function() { ... })?

Here's a small example. I'm feeling a bit rusty with JavaScript, as it's been some time since I last worked with it. The problem I'm encountering is an error in Chrome developer tools: "Uncaught TypeError: Cannot set property 'src ...

Using directive to access service values directly

I am in need of utilizing a directive to fetch and display data using ng-repeat from a service. The anticipated result will be <ul>Days <li>Monday</li> <li>Tuesday</li> ... <ul> <ul>Month <li>January</li ...

I used the `MyWindow=window.open` function to display a pop-up window and then navig

On my webpage (http://localhost:8088/hse/public/explorer), I have implemented two buttons: When these buttons are clicked, a new pop-up window will open at (http://localhost:8088/hse/public/explorer/1) onClick="MyWindow=window.open('http://local ...

Conquering disparities in standards mode with Javascript

Having an issue with this code snippet: function scrollLeft() { document.body.scrollLeft -= scrollSpeed; } While it works fine in Chrome and Safari, it doesn't seem to work in IE and Firefox. Found out that the problem lies in the fact that Fire ...

Debugging in Javascript involves pausing or breaking at every instance of a javascript function being called

I am currently working on unraveling a complex legacy JavaScript codebase, and I'm finding it challenging to determine where to place breakpoints (having to locate the files and set a breakpoint in Firebug, etc). Is there a way for Firebug to automat ...

Vue component unexpectedly refreshed without cause

I noticed that my component is being re-rendered for no apparent reason whenever the parent's data item is changed, even though it has nothing to do with the component itself. For a simple demonstration, you can check out this example here. (Clicking ...

What is the best way to retrieve the current URL with a hashtag symbol using JavaScript?

I am attempting to display the current URL after the question mark with a hash symbol using PHP, but unfortunately, it is not achievable. Therefore, I need to utilize JavaScript for this task, even though I have limited knowledge of it. This is the specifi ...

Pass the form data to the next page with javascript in HTML

While working on a website for a power plant, I encountered some issues that require assistance. The main problem is that our client does not want to set up a database on their server. This means I can only use html, javascript, and a bit of php. There is ...

Learn the best way to efficiently transfer multiple checkbox selections in a single object using AJAX

In my form, I have 4 checkboxes with unique IDs like filter_AFFILIATION_1, filter_AFFILIATION_2, and so on up to 4. My goal is to dynamically send the values of checked checkboxes to the server using an ajax call. Below is the snippet of my code: $(&a ...

Tips for creating a single div element on a React form

I have a form that is generated using the array map method in React. I am trying to add either 'box-one' or 'box-two' div element when clicking on the add button, but currently both div elements are being added. How can I ensure that on ...

What is the best way to apply a class to a jQuery element only if a specific condition is met, and then remove it if the condition is no longer

Is there a more concise method to accomplish the same task? const selectAllCheckbox = $("input.select_all"); const isChecked = selectAllCheckbox.prop("checked"); isChecked ? selectAllCheckbox.parent().addClass("selected") : selectAllCheckbox.parent().r ...

JavaScript plugin designed for effortless conversion of JSON data to structured HTML code

I want to add this JSON data to an HTML element. [ { "website":"google", "link":"http://google.com" }, { "website":"facebook", "link":"http://fb.com" } ] Is there an easy way to convert this using a plugin ...

Learn to display multiple collections of data on a webpage using Node.js and MongoDB

Struggling with displaying multiple collections on my webpage. After extensive research, I keep encountering an error message saying "Failed to look up view in views directory." Here is the code snippet causing the issue: router.get('/', functio ...