3

When switching from $scope to "controller as" syntax, I run into trouble with the "this" reference. I need to call to a service to get some data for the initial page load up. But the "this" I get refers to the global window object rather than an instance of the exercise controller. Kind of weird. Here's what I know.

The AngularJS inclusion in my main page...

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.14/angular.min.js"></script>

Here's how the controller gets included into the template page.

 <div class="col-xs-9" 
      ng-include="'exercise/exercise_body.html'" 
      ng-show="mainController.showStatus.exercises" 
      ng-controller="ExerciseController as ec" 
      ng-init="ec.initialize()"></div>

Here is the initialize function from the ExerciseController.

this.initialize = function(){
    // Item lists to display on different parts of the page
    this.dataList = {};
    this.dataList.exercises = [];
    this.dataList.resources = [];

    var promise = exerciseService.getExercises();
    promise.then(function(res){
        console.log(this); // this is a window object?  why????
        this.dataList.exercises = res.data.exercises;
    });
}

And lastly, there is the stack trace from Chrome....

TypeError: Cannot set property 'exercises' of undefined
at app.js:82
at angular.js:13189
at l.$eval (angular.js:14401)
at l.$digest (angular.js:14217)
at l.$apply (angular.js:14506)
at l (angular.js:9659)
at S (angular.js:9849)
at XMLHttpRequest.D.onload (angular.js:9790)

So what that leaves me with is a datalist object that's undefined even after setting a definition explicitly. Any ideas on what can be done to fix this or work around this issue?

2 Answers 2

3

This is very typical problem. The way callback function is provided to promise will get it called in global context. You need to bind callback function to controller context:

var promise = exerciseService.getExercises();
promise.then(function(res) {
    this.dataList.exercises = res.data.exercises;
}.bind(this));

or simply use arrow function that preserves lexical scope:

var promise = exerciseService.getExercises();
promise.then(res => this.dataList.exercises = res.data.exercises);
Sign up to request clarification or add additional context in comments.

3 Comments

Another pattern is to store a reference to the parent scope. something like var ec = this; at the top of the controller
True, for controllerAs sometimes people use something like var $ctrl = this; and then attach everything to $ctrl.
Interesting approach with ec var referencing this. I'll definitely have to try that one. Thanks, Prof Allman.
0

if you put

var vm = this;

you can use vm instead of this anywhere! :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.