Liga
Liga

Reputation: 3439

Cannot use 'this' keyword in an object because it is inside another function

I am using vue.js in this case but I guess it would apply in plain JS too. The problem is that when I am in a function that is in another function I am having to call variables by their full path like - Object.variable instead of this.variable. Is there a way to use this.timer, this.pages instead of TVComponent.pages etc.

const TVComponent = new Vue ({
el: '.tvContent',

data:
{
    current_page: 0,
    timer: 0,
    pages: [
      { page: '/', interval: 10 },
      { page: 'tv/calls', interval: 10 },
      { page: 'tv/general', interval: 10 }
    ]
},

methods:
{
  tvTimer()
  {
     setInterval(function() {
        TVComponent.timer++;

        if (TVComponent.timer == TVComponent.pages[TVComponent.current_page].interval) {
           console.log('it is time!!');
        }

        console.log(TVComponent.pages[TVComponent.current_page].page);
     }, 1000);
  },
})

Upvotes: 4

Views: 747

Answers (4)

Nikola Kirincic
Nikola Kirincic

Reputation: 3757

This is because setInterval() this object is not same as vue.js this, since they have different scopes.

Try to assign this object to new variable before entering the problematic function's scope.

let self = this;
tvTimer()
  {
     setInterval(function() {
        self.timer++;

        if (self.timer == self.pages[self.current_page].interval) {
           console.log('it is time!!');
        }

        console.log(self.pages[self.current_page].page);
     }, 1000);
  },

See: https://developer.mozilla.org/en-US/docs/Glossary/Scope

Upvotes: 0

Linus Borg
Linus Borg

Reputation: 23968

Classic problem of this being not what you expect in a function

A. bind it

methods:
{
  tvTimer()
  {
     setInterval(function() {
        // ...
     }.bind(this), 1000);
  },
})

B. use a closure

methods:
{
  tvTimer()
  const _this  = this
  {
     setInterval(function() {
        _this.timer ...
     }, 1000);
  },
})

C. use an arrow function

methods:
{
  tvTimer()
  {
     setInterval(() => {
        this.timer ...
     }, 1000);
  },
})

This is one of those things one has to really understand about JS in order to not fall for it over and over in different places. I suggest this ebook:

https://github.com/getify/You-Dont-Know-JS/blob/master/up%20%26%20going/ch2.md#this-identifier

Upvotes: 2

UncleDave
UncleDave

Reputation: 7188

The function you pass to setInterval receives its own context, however if you use an arrow function it will use the current context instead, and ignore the one given by setInterval.

setInterval(() => { ... }, 1000)

Upvotes: 1

Shakeel Ahmed
Shakeel Ahmed

Reputation: 41

I think you have to bind it in this context. We do it this way in React classess.

Upvotes: -1

Related Questions