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/

Also read...

Leave a Reply

Your email address will not be published. Required fields are marked *