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?
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/
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>
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
}
})