简体   繁体   中英

Vue.js class binded to object is not changing on object update

I have a number of buttons, being generated wuth v-for directive. all of them have initial class, based on the string from an object. I have an event, that is changing this string on button click. But the class is not being updated. What am i doing wrong?

<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] == this.winId) {
                alert('you win');
                this.cells[id].color = 'success';
            } else {
                this.cells[id].color = 'warning';
            }
        }
    },
    created() {
        this.generateCells();
    }
}

</script>

I expect the button class to be updated upon respected object update. The object .color prperty is updated but the class remains initial.

Due to the limitations of modern JavaScript (and the abandonment of Object.observe), Vue cannot detect property addition or deletion. Since Vue performs the getter/setter conversion process during instance initialization, a property must be present in the data object in order for Vue to convert it and make it reactive.

Read more here: Reactivity in Depth .

Vue provides an API to add properties to nested level objects and to make them reactive.

To do so, you can use

Vue.set(object, propertyName, value);

You can also use the vm.$set method

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

So in your code, where you are setting the value of array you need to do

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

See the complete snippet 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>

Read in detail about data and methods in the Vue documentation .

It should be noted that properties in data are only reactive if they existed when the instance was created. That means if you add a new property,like:

 vm.b = 'hi'

Then changes to b will not trigger any view updates.

you can use Vue.set() or this.$set() api when you set the prop value in loop.

or replace the whole object like:

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

and then, in click callback:

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM