Reputation:
I am learning Vue.js and at the moment i am learning to interact with the css, i really would love to know why my code doesn't work, basicly i have a button, when i click that button, every 1 second (i used setInterval for this, i tested the setInterval and it works) it should change between 2 classes that i have defined on my css, i have a higlight class, and a shrink class, and it should swap with each other in 1 second, when i enter the example, the second class is attached but passed 1 second no change happens, can you guys explain me why?
Html relevant part
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<script src="https://unpkg.com/[email protected]"></script>
<div id="exercise">
<!-- 1) Start the Effect with the Button. The Effect should alternate the "highlight" or "shrink" class on each new setInterval tick (attach respective class to the div with id "effect" below) -->
<div>
<button @click="startEffect">Start Effect</button>
<div id="effect" :class="{highlight: effect,shrink: !effect}"></div>
</div>
Css
#effect {
width: 100px;
height: 100px;
border: 1px solid black;
}
.highlight {
background-color: red;
width: 200px !important;
}
.shrink {
background-color: gray;
width: 50px !important;
}
Javascript
new Vue({
el: '#exercise',
data: {
effect: true,
},
methods: {
startEffect: function() {
setInterval(function(){
this.effect = !this.effect;
console.log(this.effect);
},1000);
}
}
});
Upvotes: 2
Views: 608
Reputation: 9549
You lost context of your component
inside the setInterval
so your this
is not the vue-component
as you'd expect.
new Vue({
el: '#exercise',
data: {
effect: true,
},
methods: {
startEffect: function() {
console.log(this) // add this line
setInterval(function() {
this.effect = !this.effect;
console.log(this) // with this line, it will show you what went wrong
console.log(this.effect);
},1000);
}
}
})
You can either do:
new Vue({
el: '#exercise',
data: {
effect: true,
},
methods: {
startEffect: function() {
setInterval(() => {
this.effect = !this.effect;
console.log(this.effect);
},1000);
}
}
})
This works because with arrow functions
this
is bound to the enclosing scope.
or (ES5)
new Vue({
el: '#exercise',
data: {
effect: true,
},
methods: {
startEffect: function() {
var vm = this
setInterval(function() {
vm.effect = !vm.effect;
console.log(this.effect);
},1000);
}
}
})
This works as you are no longer using this
inside the setInterval's
callback but a variable vm
that holds the context of your component.
See it working
new Vue({
el: '#exercise',
data: {
effect: true,
},
methods: {
startEffect: function() {
setInterval(() => {
this.effect = !this.effect;
console.log(this.effect);
},1000);
}
}
})
#effect {
width: 100px;
height: 100px;
border: 1px solid black;
}
.highlight {
background-color: red;
width: 200px !important;
}
.shrink {
background-color: gray;
width: 50px !important;
}
<script src="https://vuejs.org/js/vue.min.js"></script>
<div id="exercise">
<!-- 1) Start the Effect with the Button. The Effect should alternate the "highlight" or "shrink" class on each new setInterval tick (attach respective class to the div with id "effect" below) -->
<div>
<button @click="startEffect">Start Effect</button>
<div id="effect" :class="{highlight: effect,shrink: !effect}"> </div>
</div>
Upvotes: 4