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="//"></script>
<script>// <![CDATA[
function MyCtrl ($scope){
    $scope.showMySelect = true;
    $scope.opts = [1,2,3];
    $scope.mySelectValue = 2;
// ]]></script>

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:


$scope.mySelectValue = { "val" : 2 };



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

Also read...

Leave a Reply

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