Ng-if is similar to ng-show in some way. They both can be used to hide HTML elements. While they seem alike, the differences are not subtle. If you use them, you need to know exactly what makes them different. Although in some cases they can be used interchangeably, in some they cannot.
There are two main facts that make them two different directives: the way they hide HTML elements and variables/scope management.
How ng-if hides elements?
Ng-show changes the display CSS property of the HTML element to hide or show it. It is a behavior purely focused on styles. It operates on the visual side of the page.
Ng-if does it in a totally opposite way. If an element must be hidden, it is totally removed from the DOM. Let's see it on an example.
<p>This is a test.</p>
<p ng-if="1 === 1">A text with ng-if directive.</p>
The above code is displayed in the browser as below (it can be shown by using the Inspect element feature available in the most modern browsers):
<p>This is a test.</p>
<!-- ngIf: 1 === 1 --><p ng-if="1 === 1" class="ng-scope">A text with ng-if directive.</p><!-- end ngIf: 1 === 1 -->
If the condition is changed to false, the second paragraph should disappear.
<p>This is a test.</p>
<p ng-if="1 === 0">A text with ng-if directive.</p>
It results in the following HTML rendered by a browser.
<p>This is a test.</p>
<!-- ngIf: 1 === 0 -->
The second paragraph is not even visible. AngularJS removed it completely from the code of the page. It makes it lighter and cleaner.
Variables and scope
Removing elements from the DOM is not the only difference. Another one is creating a child scope by ng-if.
It has important implications. For example the following code does not work as expected.
<form>
<input type="radio" name="place" value="country" ng-model="place" />country
<input type="radio" name="place" value="city" ng-model="place" />city
<div ng-if="place === 'country'">
<p>Country name
<input type="text" name="countryName" ng-model="location.country" /></p>
<p>country = {{location.country}}</p>
</div>
<div ng-if="place === 'city'">
<p>City name
<input type="text" name="cityName" ng-model="location.city" /></p>
<p>city = {{location.city}}</p>
</div>
</form>
<h2>Scope:</h2>
<p>place = {{place}}</p>
<p>location = {{location}}</p>
Scope:
place = {{place}}
location = {{location}}
After selecting the city radio and typing a name, the location.city variable changes but it is printed only inside the div element. The location variable at the end of the page remains null. It is a direct consequence of using a new child scope for the variables under the ng-if directive. They are simply invisible from the parent scope.
If you compare this example with the one from the ng-show post, you will see that it was not a problem there. Ng-show operates on the display CSS property only and it does not create a child scope.
How to access the variable inside ng-if? you may ask. The above example can be easily modified to work by adding the following line in the controller:
$scope.location = {};
It creates the location variable in the parent scope. Then the child scopes can modify it without creating the location variable in the child scope.