7

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

the_camino
  • 356
  • 5
  • 18
  • Please review http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback – charlietfl Feb 26 '16 at 18:23

3 Answers3

14

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.

Dmitri Pavlutin
  • 18,122
  • 8
  • 37
  • 41
2

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);
}
})
Andrés Esguerra
  • 849
  • 5
  • 15
0

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

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

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

    this.runTimeoutExample = function(){
        $timeout(function(){
           doSomething();
        }, 1000);
    }
});
 app.controller('main-controller', function($scope, ToolService) {
   
    $scope.somethingWasClicked = function() {
    
        ToolService.runTimeoutExample();
    };

});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test-module" ng-controller="main-controller">
  
  <input type="button" value="click" ng-click="somethingWasClicked()">
  
  </div>
Hadi J
  • 16,989
  • 4
  • 36
  • 62