Issue
I am trying to understand the working of ng-if in contrast with ng-show.
After reading the docs and going through the related stackoverflow question here, I understand that ng-if removes the DOM element and the scope variables inside that ng-if are removed.i.e ng-model variables inside the ‘removed’ ng-if element wont appear in $scope.
From the Angular ng-if docs:-
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.
Consider following code snippet:-
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.10/angular.min.js"></script>
</head>
<body data-ng-app="myModule">
<div data-ng-controller="TestController">
<input name="first" type="number" data-ng-model="form.x" placeholder="Enter Number X"/>
<input name="second" type="number" data-ng-if="form.x>5" data-ng-model="form.y" placeholder="Enter Number Y"/>
<input type="button" value="Click" ng-click="save()"/>
</div>
<script type="text/javascript">
var myModule = angular.module("myModule",[]);
myModule.controller("TestController",function($scope){
$scope.form = {};
$scope.form.x = 0;
$scope.form.y = 0;
$scope.save = function(){
console.log($scope.form);
};
});
</script>
</html>
This is pretty simple use case – show the second number input field only when first is greater than 5.
The save button click delegates to ‘save’ function in the controller which simply prints out the ‘form’ object of $scope.
Problem:-
Input 1:-
Enter x=6 and y=2
Output 1 : {x: 6, y: 2}
Input 2:-
Enter x=3
Output 2 : {x: 3, y: 2}
I am not able to understand why ‘output 2’ still shows y =2. If its DOM has been removed, shouldn’t the output be just {x:3} ?
What should I do if I want to remove (ngIf-removed) model from the scope?
Thanks
Solution
Problem
To further what @Chandermani pointed out in comments, ng-if
creates a new scope, which has its own variables. It does, however, prototypically inherit from its parent scope, so if you set a property on an existing parent object, such as what you’re doing by using form.y
, when the child scope is destroyed, that property remains unaffected.
Quick fix solution
You could add another directive to the same element as the one you’re setting ng-if
on, which delete
s the property from the scope on $destroy
:
Directive
myModule.directive('destroyY', function(){
return function(scope, elem, attrs) {
scope.$on('$destroy', function(){
if(scope.form.y) delete scope.form.y;
})
}
});
View
<input ... data-ng-if="form.x>5" destroy-y .../>
Note: I saw that @user2334204 posted something similar. I decided to post this anyway because here the value of x won’t have to be checked every digest
Answered By – Marc Kline
This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0