ericmux
ericmux

Reputation: 138

Is 'this' truly a reference to "$scope" in AngularJS's context?

I'm quite new to the superheroic framework AngularJS, so please excuse my noobness! So, while I was trying to develop a simple SPA that allowed admins to change permissions of other users in my website through a table filled with selection checkboxes, I came by an issue. I defined $scope.checked so I could know how many users the administrator chose and also $scope.mainCheckBox which would hold the correct CSS class for the major checkbox (like the one from Gmail, which you use to select all/none) in each of the three situations: all users selected, no users selected and partial selection. This simple logic goes as follows:

$scope.updateMainCheckBox = function(){

    if(this.checked==this.users.length) this.mainCheckBox = "qm-icon-checked";
    else if(!this.checked) this.mainCheckBox = "";
    else this.mainCheckBox = "qm-icon-minus";

};

Running this at the end of the ng-click event callback of the other checkboxes, this code was capable of choosing the class correctly but it wouldn't assign the class to the mainCheckBox. When I changed every this.mainCheckBoxto $scope.mainCheckBox it all went well and the page would behave as expected.

So, I know in vanilla Js this is a reference to the window object but since AngularJS has its own event handling loop, I believe that's not the case now. I expected it to be a ref to $scope, since checked and users were found, but apparently it's not. So, what's happening here? And also, is there a more "angular" way to implement this?

Upvotes: 1

Views: 443

Answers (1)

Michelle Tilley
Michelle Tilley

Reputation: 159135

You're mostly right--in the case of your function, this did reference a scope. But, it did not reference $scope; instead, it referenced one of $scope's children.

Try this: add some console.log statements to log out the ID of the $scope variable, and then the ID of the this scope in your callback:

$scope.updateMainCheckBox = function(){
  console.log('$scope:', $scope.$id);
  console.log('this:', this.$id);
  // ...
};

You'll find the IDs are different. This is because the ngRepeat directive creates a child scope, which is a scope that inherits prototypally from its parent. This means that when you assign directly to a value on that scope, it's not reaching the parent scope, which is $scope.

I highly recommend a read through the excellent (and lengthy) "The Nuances of Scope Prototypal Inheritance" by Mark Rajcok; it esplains why you see this seemingly strange behavior on child scopes. (You can also find a copy on the AngularJS wiki.)

Upvotes: 2

Related Questions