2

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/vue@2.2.1"></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);
    }
  }
});

1 Answers1

3

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>
Amresh Venugopal
  • 8,159
  • 4
  • 33
  • 48
  • it worked perfectly, i already saw something like that, and i know it has nothing to do with vue.js directly, but with javascript, can you just explain me why the 'this' is lost? –  Mar 06 '17 at 12:59
  • That would be a lot to explain and outside the scope of this question but I can link you to this http://stackoverflow.com/questions/591269/settimeout-and-this-in-javascript and http://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work. If you couldn't understand you can contact me :) – Amresh Venugopal Mar 06 '17 at 13:01
  • hmmm i didn't understand very well the example, do you know a simpler example to understand this?.. because i think this is really important since this is pure javascript :D –  Mar 06 '17 at 13:09
  • can't talk on chat don't have 20 reputation xD –  Mar 06 '17 at 13:13
  • Then run these in your console https://gist.github.com/CodeWingX/97a5381a9aa46c94d42577524ea90b28 – Amresh Venugopal Mar 06 '17 at 13:41
  • i saw every topic that you refered and learned something about it, but have some question about those, i already knew that 'this' referes to the context, so i can access for example the properties of a object in my context, but what confuses me is, when do javascript create a new context? everytime i define a new scope? –  Mar 06 '17 at 18:03
  • http://stackoverflow.com/a/13418980/5756583 take the next set on the comments on the gist please. – Amresh Venugopal Mar 06 '17 at 18:09