1

This is not exactly a question with some code, but more for my understandings. So please forgive me if this isnt appropriate here..

I was playing with a simple checkbox with an ngModel assigned:

<input type="checkbox" ng-model="someFlag"/>

I expect this to bind the boolean of the checkbox to $scope.someFlag (if controller and everything else configured properly). And yes, it does work. But there are times where I found that this is not working. Case: When I try to do something when the someFlag changes (for example in a $watch) the value is not really binded.

But then I came accross something a collegua at work mentioned once:

Use a wrapper object

Doing it like that works now without any problems:

<input type="checkbox" ng-model="wrapperObject.someFlag"/>

Watching $scope.wrapperObject.someFlag works as expected.

Now the question: Why??

David Fariña
  • 1,536
  • 1
  • 18
  • 28
  • possible duplicate of [AngularJS: If you are not using a .(dot) in your models you are doing it wrong?](http://stackoverflow.com/questions/18128323/angularjs-if-you-are-not-using-a-dot-in-your-models-you-are-doing-it-wrong) – anvarik Jun 06 '14 at 14:11
  • Have a look to this video which is taken from Egghead.io, your problem is explained [here](http://www.youtube.com/watch?v=DTx23w4z6Kc). – anvarik Jun 06 '14 at 14:03

4 Answers4

3

When ngModel directive is executed, it reads attribute's ng-model value (in this case, "someFlag") and saves it in it's local function scope (not to confuse to angulars $scope). But since a boolean in javascript is a primitive, you cannot pass it by reference, only by value. That means only the $scope.someFlag's value (true or false) get's copied to ngModel, and not the way of accessing and modifying $scope.someFlag from ngModel.

When you use wrapper object, it is passed by reference, meaning, it is the same thing both in $scope.wrapperObject and in ngModel's local function scope, because it points to the same memory address behind the scenes.

I'm not sure if this explanatory enough, but when working with primitive values in angular, you must keep in mind the difference between passing by reference and by value and that when primitive's change, other parts of application might not know this.

package
  • 4,741
  • 1
  • 25
  • 35
  • That was exacltly what i wanted to know: But since a boolean in javascript is a primitive, you cannot pass it by reference, only by value. – David Fariña Jun 06 '14 at 14:12
1

In my understanding you want to pass Boolean value if check box checked to controller

try this: In your html:

<input type="checkbox" ng-model="value"
                 ng-true-value="YES" ng-false-value="NO"> <br/>

in your controller:

$scope.value is gives Boolean value// 
chandu
  • 2,276
  • 3
  • 20
  • 35
1

This is because scope inheritance. A nice article about angularjs scope and inheritance

I guess the $watch logic you mentioned might have been triggered from inside a ng-repeat or a ng-if. Remember angularjs creates a new scope variable for each object inside ng-repeat and ng-if.

<input type="checkbox" ng-model="someFlag"/> //This is a primitive $scope.someFlag

<input type="checkbox" ng-model="obj.someFlag"/> //This is an object $scope.obj.someFlag

<div ng-repeat="opt in options"> Here a new child scope - $scope.somechild is created for the opt variable. So if primitive variable someFlag is referenced here it will be taken as $scope.child.someFlag. so any update here will not update the parent $scope.someFlag. But if an object obj.someFlag is referenced here by object inheritance the compiler will try to find obj.someFlag in child - $scope.child as it is not present it will search in parent $scope as it is present this will now refer to $scope.obj.someFlag and any modification done here is done in the actual parent scope.

guru
  • 4,002
  • 1
  • 28
  • 33
1

This is part of the mantra: "there should always be a dot in your model" by Misko Hevery, one of the fathers of Angular. You can, and probably should, watch this video: https://www.youtube.com/watch?v=ZhfUv0spHCY&feature=youtu.be&t=32m51s

ngModel is a directive that does two-way-data-binding. Binding to a primitive (Boolean in this case) will make the setter to set it on the current scope, rather than on the scope that's defined which could interfere with other scopes.

In your scenario, in a parent scope we have your $scope.someFlag = true. In a child scope we then have your input:

<input type="checkbox" ng-model="someFlag"/>

That will work initially but once the user changes the value, the someFlag will be created on the child scope and the bindings will read and write from that value from now on.

I hope this is, somehow, clear.

Note that this only happens with two-way-data-binding directives and not regular ones such as ngDisabled or ngHide

Antonio Laguna
  • 8,973
  • 7
  • 36
  • 72