20

I am trying to understand ng-if and scopes. As I am aware, ng-if creates a new child scope. Here is my issue:

View

<input ng-model="someValue1" />
<div ng-if="!someCondition">
    <input ng-model="$parent.someValue2" />
</div>

Controller

$scope.someCondition = true;

if ($scope.someCondition) {
    $scope.someValue2 = $scope.someValue1;        
}

If someCondition is set to true, then someValue2 should be the same as someValue1.

My problem is that I can't access someValue2 in both situations (true or false). How could I achieve this?

2
  • 3
    In angular you must never ever modify $parent properties value directly. However you can modify property of $parent properties or you'll break inheritance. do : $parent.someValue.num = 10, don't : $parent.someValue = 10 Commented Jun 11, 2015 at 17:16
  • This statement is not backed up in any way. Modifying $parent properties seems to work perfectly fine. The "already answered here" question at the very top has an answer that explains how modifying $parent properties works, even with some visualization, and it clearly shows that it works. One problem is that when adding more conditions and ng-ifs or creating some other child scopes, there may be a longer chain of $parents and the code breaks, unlike when using objects. Actually, you don't even need $parent when using those objects, just use $scope: $scope.someValue.num = 10. Commented Jul 21, 2020 at 9:07

3 Answers 3

33

Yes, ng-if creates a new child scope

To watch a model property in an ng-if, the rule-of-thumb is:

DO NOT USE THE SCOPE AS MODEL

e.g.

ng-if='showStuff' //here my scope is model **INCORRECT**
ng-if='someObject.showStuff' // ** CORRECT **

Use an object property in ng-model - then, even if ng-if creates the new child scope, the parent scope will have the changes.

To see a working Plunker, look here : http://jsfiddle.net/Erk4V/4/

Sign up to request clarification or add additional context in comments.

2 Comments

Why does this work? Both $scope and someObject are just objects, right? What makes someObject different? I am intending to name it scope in my project and it seems rather silly to have both $scope and scope.
I checked out the "already answered here" question at the very top and its answer provided some insight :)
16

ngIf does indeed create a new scope using prototypal inheritance. What that means is that the ngIf's scope's prototype object is that of its parent's scope. So if the attribute isn't found on the ngIf instance of its scope it will look into its prototype objects chain for that attribute. However, once you assign an attribute to the instance of the scope it will no longer look into its inheritance chain for the attribute. Here's a link explaining prototypal inheritance used in JS: https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance

How to solve this:

Parent controller:

$scope.data = {someValue: true};

Child controller:

$scope.data.someValue = false

Because you're not hiding an attribute on its parent's scope, you're just mutating an object on its parent's scope, this will indeed alter the parent's data object. So in your case:

<input ng-model="data.someValue1" />
<div ng-if="!data.someCondition">
    <input ng-model="data.someValue2" />
</div>

4 Comments

I will dive into it, thank you :)
user2734679 can you give me another explanation perhaps? With certain values of someValue. Unfortunately I still don't get it.
This isn't an angular thing. It's a javascript thing. So here's some examples of prototypal inheritance.
There should be a link?
-9

From what I'm aware of, the ng-if is purely a display level statement. You can use it to make some elements visible / invisible given certain values but I don't think it creates any kind of scope. What your HTML code will do is toggle the visibility of your secondary input.

If you'd like to switch your Value 2 to equal Value 1 whenever "someCondition" changes between false and true, then you can use $watch with something like this:

$scope.$watch(someCondition, function(){
  if (someCondition){
    $scope.someValue1 = $scope.someValue2
  }
})

7 Comments

Thank you for your comment. My condition is on scope as well, so i dont think i need to watch it.
No. ngIf differs from ngShow, ngHide in that it doesn't just hide the html element. It completely destroys it. And it does indeed create a new scope using prototypal inheritance. docs.angularjs.org/api/ng/directive/ngIf
@user2734679 Nice dude, thanks for the link! I learn something new about Angular every day :-)
this answer should be deleted
ng-if has its own scope , and $watch in controller won't watch it, unless you are using it into directive that has ng-if scope.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.