ng-if/ng-switch breaks ng-model? No, it’s just a matter of understanding scopes
Lately I’ve been working on an AngularJS project, and I incurred on something that at first I considered a bug. Here’s some example code:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
<script>// <![CDATA[
function MyCtrl ($scope){
$scope.showMySelect = true;
$scope.opts = [1,2,3];
$scope.mySelectValue = 2;
}
// ]]></script>
<div><section>{{mySelectValue}}
<select></select></section></div>
I wanted to update $scope.mySelectValue
with the selected value in the select. Simple as that. But this code doesn’t work as I expected.
What puzzles at first is that in the controller we set $scope.mySelectValue
to 2, and the select actually shows 2 as the selected value. But if we change the value in the select, the model doesn’t update. How come that the model binding isn’t bi-directional as usual?
This behaviour is caused by ng-if
: in fact, this angular directive creates a new scope. So, as usual in JavaScript, it’s all a matter of scopes.
When using angular’s 2-way data binding to a primitive (e.g. number, string, boolean), the model won’t update. Here the child scope can read the parent scope, but can’t update it.
Possible solutions:
1) use $parent
to refer to the parent’s scope: ng-model=“$parent.mySelectValue"
2) bind to a object instead of a primitive:
Controller:
...
$scope.mySelectValue = { "val" : 2 };
...
View:
...
<select></select>
...
3) (not suggested) use ng-show
/ng-hide
directives instead of ng-if
. This isn’t suggested because it could pollute the scope (and increase memory usage), since the elements are created in every case then just shown or hidden.
Ng-if
directive was introduced in angular 1.1.5. This behaviour also exists with ng-switch
and ng-repeat
directives (already present in older versions)
Further reference
https://github.com/angular/angular.js/wiki/Understanding-Scopes
https://github.com/angular/angular.js/issues/7216#issuecomment-41185572
https://www.youtube.com/watch?v=ZhfUv0spHCY&feature=youtu.be&t=30m
http://jsfiddle.net/r4RKW/1/