AngularJS: ng-if not working in combination with ng-click?

Given this test case using AngularJS 1.2 rc3: http://plnkr.co/edit/MX6otx (repeated below)

1.

<li ng-init="toggle1 = false">
    ng-if toggle1: {{ toggle1 }}
    <p>
        <button ng-if="!toggle1" ng-click="toggle1 = true">Turn On</button>
        <button ng-if="toggle1" ng-click="toggle1 = false">Turn Off</button>
        does not work
</li>

2.

<li ng-init="obj={toggle2:false}">
    ng-if obj.toggle2: {{ obj.toggle2 }}
    <p>
        <button ng-if="!obj.toggle2" ng-click="obj.toggle2 = true">Turn On</button>
        <button ng-if="obj.toggle2" ng-click="obj.toggle2 = false">Turn Off</button>
        then why does this work?
</li>

Questions:

  1. Why does 1 not work?
  2. Should 1 work?
  3. Why does 2 work?
  4. Should 2 work?
  5. Can I rely 2 to work in future updates of AngularJS?

Answers:

Answer
  1. Why does 1 not work?: Because an ngIf defines its own scope, which prototypically inherits from its parent scope (just like ngRepeat). So, when you change the value of a field inside an ngIf, you change it in the ngIf scope, and not in its parent scope.
  2. Should 1 work?: No
  3. Why does 2 work?: Because in that case you modify the content of an object which is referenced by the ngId scope, through inheritance.
  4. Should 2 work?: Yes
  5. Can I rely 2 to work in future updates of AngularJS?: Why shouldn't you?

This scope inheritance mechanism is explained very well in https://github.com/angular/angular.js/wiki/Understanding-Scopes

Answer

Since ngIf creates own scope, to make it work you can define toggle1 in one scope:

JS**

$scope.toggleMe = function(){
     $scope.toggle1 = !$scope.toggle1;
    }

HTML

<li ng-init="toggle1 = true">
        ng-if toggle1: {{ toggle1 }}
        <p>
            <button ng-if="toggle1"  ng-click="toggleMe()">Turn On</button>
            <button ng-if="!toggle1"  ng-click="toggleMe()">Turn Off</button>
            does not work
    </li>

See Demo Plunker

Answer

1. Why does 1 not work?
ng-if creates a new scope. which causes the "weird" binding behavior as explained in this video: http://egghead.io/lessons/angularjs-the-dot

2. Should 1 work?
Reading properties from the parent scope works (prototype chain), but writing to the scope creates a new property on the child scope. Creating a disconnected

3. Why does 2 work?
The same property is read from the parent scope (obj). The write in ng-click changes the "obj" object, not the scope.

4/5. Should 2 work? Can I rely 2 to work in future updates of AngularJS?
YES, this is the documented expected behavior.

Tip: I use the Chrome extension AngularJS Batarang to gain insights about which variables are on which scope.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.