Often times the choice between both directives seems trivial, because you can achieve the same effect either way. However both have interesting default behaviours that you can use to you advantage.
ng-showwill hide the element it is on by default, unless the condition in it evaluates to true.ng-hidewill show the element it is on by default, unless the condition in it evaluates to true.
This is most useful when your controller is doing AJAX calls or something else that's asynchronous. Your variables may still be undefined until the AJAX call returns.
foo.controller.js
$ctrl.foos;
//...
$http.get('get/all/foos').then(function(response) {
$ctrl.foos = response.data; //Assume that this will be an array
});Above we can see that the controller requests a value for foos from the server. The value of foos will be undefined until the AJAX returns.
foo.template.html
<p ng-show="$ctrl.foos.length <= 0">
No FOOs have been found
</p>Above we want the message to show only after the AJAX is done and it returned an empty array. Otherwise it should be hidden.
If you think about the condition $ctrl.foos.length <= 0 you will realise that this will throw an exception if $ctrl.foos is undefined. So you may be tempted to do additional checks, such as $ctrl.foos && $ctrl.foos.length <= 0 to prevent an error to be thrown. However this may open the door to even more unexpected border-line bugs, such as what if foos has the value "banana". Instead we can make clever use of ng-show's default behaviour.
Recall that the default behaviour for ng-show is that it will hide the element unless the condition in it evaluates to true. So in this case we can just use ng-show="$ctrl.foos.length <= 0" and we will know that the element will be hidden if the AJAX hasn't returned yet or if $ctrl.foos is a weird value.