1

I'm finding this issue strange.

Basically I want a block to exist on a page based on an ng-if condition. But when I try to modify that ng-if inside said block, it doesn't have any effect on any other elements.

Why is this happening?

The JSFiddle is here and the code is below:

<div ng-controller="MyCtrl">
    <div ng-init="shouldShow=false">
        <div ng-if="!shouldShow">
            <p>{{shouldShow}}</p>
            <div>
                <button ng-click="shouldShow=!shouldShow">Hide Section</button>
                <button ng-if="!shouldShow">Should Disappear</button>
            </div>
        </div>
    </div>
</div>
CodyBugstein
  • 21,984
  • 61
  • 207
  • 363

2 Answers2

1

This is an issue with ng-if child scope and the fact you are trying to 2-way bind a primitive in a child scope.

You should always try to use objects in your scope as models so that you leverage the benefits of prototypical inheritance.

See the difference here:

<div ng-controller="Ctrl">
      <div >
        <p>{{model.shouldShow}}</p>
        <div ng-if="!model.shouldShow">
            <button ng-click="model.shouldShow=!model.shouldShow">Hide Section</button>
            <p>{{model.shouldShow}}</p>
        </div>
    </div>
</div>

JS

function Ctrl($scope) {
    $scope.model={shouldShow:false}
}

Also read the docs for ng-init. It should not be used for arbitrary variables. It's main purpose is for aliasing variables in ng-repeat

DEMO

charlietfl
  • 170,828
  • 13
  • 121
  • 150
1

The documentation of ng-if explains what happens:

Note that when an element is removed using ngIf its scope is destroyed and a new scope is created when the element is restored. The scope created within ngIf inherits from its parent scope using prototypal inheritance. An important implication of this is if ngModel is used within ngIf to bind to a javascript primitive defined in the parent scope. In this case any modifications made to the variable within the child scope will override (hide) the value in the parent scope.

In short: Once you modify shouldShow in the child scope, it overrides the shouldShow of the parent scope (prototypical inheritance). As pointed out in another answer, this can be solved with an indirection via a shared object: wrapperObject.shouldShow. Unless you assign a new value to wrapperObject in the child scope it will point to the same instance as the parent scope (and therefore contain the same instance of shouldShow).

lex82
  • 11,173
  • 2
  • 44
  • 69