As others have answered, the short solution is to use ng-show instead of ng-if or to not use $compile like that.  With that aside, you might have your good reasons why you would want to use ng-if and $compile like this.
This question interested me on the note of using $compile with an isolate scope from ng-if.  I did a bit of experimenting with this fork and will try to explain what I found.
We already know ng-if creates an isolate scope, but then passing that element with ng-if on it through $compile creates another isolate scope (and would make the newly compiled ng-if be looking at variables on the first-round isolate scope - the directive's $scope value).
To re-iterate that, we're having some scopes looking like (value in [] is scope.$id):
- main/outer controller has - scope[2]
 
- ng-if my-testelement has- ng-iflooking at- scope[2].countand creates- scope[3]
 
- my-testlinker therefore has- $scope.$id == 3;
 
- my-testdoes- $compile- recompiled- ng-ifelement: creates new isolate- scope[4]and is looking at- scope[3].count
 
- when - scope[2].counthits 0 -- scope[3]gets- $destroyed(because- scope[3]was created by that first- ng-ifwhich is still lingering around somewhere) ... BUT!  the element is A. still there and B. its count isn't updating - WHY?
 
Well because the element that's still there is the one that was $compiled and has A. an ng-if looking at scope[3].count (which is now $destroyed) and B. its own new isolate scope[4] (created by re-compiling ng-if element with parent scope[3])
So ya.  That is all very confusing and you might just be asking... well how do I fix this??
TL;DR;
The simplest solution:
$element.removeAttr('ng-if'); before you do $compile($element)($scope);
If you've been following along, this works because the original ng-if is still looking at scope[2].count, and the element that is present is no longer getting a second isolate scope.