1

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?

ericmux
  • 138
  • 1
  • 9

1 Answers1

2

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.)

Community
  • 1
  • 1
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • 1
    Another good SO question/answer I found: http://stackoverflow.com/questions/11605917/this-vs-scope-in-angularjs-controllers/14168699#14168699 – Michelle Tilley May 12 '13 at 02:37
  • Cool, I think I got it! Prototypal inheritance is weird, I'm still not used to it completely and thanks, I didn't know nested directives could create child scopes! Now it makes sense! – ericmux May 12 '13 at 02:57