I have a directive that does the following:
$compile()
on the element to make AngularJS re-compile the element so the new directive is attached.This works fine, except when I also add an ng-if to the element. See this minimal example and follow the steps below to demonstrate.
https://embed.plnkr.co/ymk0RwGopGF1KvesWmvA/
+
any number of times to add to "count".0
to reset "count".+
any number of times again.I'd expect the "my-test shown" <p>
tag to be deleted from the DOM once its ng-if
condition is no longer true after step #2. Instead, it stays around, and you'll see an extra copy of the message after step #3.
I assume calling $compile($element)($scope);
in the my-test directive link function is having some unintended consequence, but I don't understand what's going on here. Any ideas?
Thanks, David
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.