Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS 'this' reference in $timeout function not working

I have an AngularJS question that is driving me absolutely crazy. I have a service that looks like this (this is an example to illustrate the issue)

var app = angular.module('test-module');

app.service('ToolService', function($timeout){

    this.doSomething = function() {
       console.log("y u no referenced as method?!?");
    }

    this.runTimeoutExample = function(){
        $timeout(function(){
            this.doSomething();
        }, 1000);
    }
})

My controller looks like this:

var app = angular.module('test-module', []);

var ctrl = app.controller('main-controller', function($scope, ToolService) {

    $scope.somethingWasClicked = function() {
        ToolService.runTimeoutExample();
    }

});

Here's the issue, when the button that was clicked that calls $scope.somethingWasClicked it forwards the call to the service and I get an error saying "this.doSomething is not a function".

Why? And how do I fix this? I'm having a hard time finding a way around needing my code to run like this without adding unnecessary logic into my controller.

Thanks in advance for your help

like image 255
the_camino Avatar asked Feb 26 '16 16:02

the_camino


2 Answers

You have 2 options:

1) Using bind() method of the function object:

Change the context of the timeout callback, to reach the controller this:

this.runTimeoutExample = function(){
    $timeout(function(){
        this.doSomething();
    }.bind(this), 1000);
}

2) Create a special variable self, to keep the link to main service function context:

var app = angular.module('test-module');

app.service('ToolService', function($timeout){
    var self = this;     
    self.doSomething = function() {
       console.log("y u no referenced as method?!?");
    }

    self.runTimeoutExample = function(){
        $timeout(function(){
            self.doSomething();
        }, 1000);
    }
})

If every time using self, you'll be sure that no context lost will happen.

Read more about the context of a function.

like image 81
Dmitri Pavlutin Avatar answered Nov 18 '22 13:11

Dmitri Pavlutin


the function inside timeout has a different scope as it is not a function belonging to the controller. Assign this to a variable before timeout, and then use that variable:

var app = angular.module('test-module');

app.service('ToolService', function($timeout){

this.doSomething = function() {
   console.log("y u no referenced as method?!?");
}

this.runTimeoutExample = function(){
    var self = this;
    $timeout(function(){
        self.doSomething();
    }, 1000);
}
})
like image 2
Andrés Esguerra Avatar answered Nov 18 '22 11:11

Andrés Esguerra