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-test element has ng-if looking at scope[2].count and creates scope[3]
my-test linker therefore has $scope.$id == 3;
my-test does $compile - recompiled ng-if element: creates new isolate scope[4] and is looking at scope[3].count
when scope[2].count hits 0 - scope[3] gets $destroyed (because scope[3] was created by that first ng-if which 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.