Reputation: 43
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
Upvotes: 4
Views: 806
Reputation: 2188
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.
Upvotes: 1
Reputation: 1920
As far as I can understand, when you change the value of count with 0, your directive is destroyed before changing the value of count
. So that unremoved directive's count value is still 1.
If you use ngShow instead of ngIf, you can solve this. Because ngShow attribute doesn't trigger $destroy event and doesn't remove element from your view. So that directive can catch new value of that count
. Or you can use prelink
instead of link
for catching updating of value of count
.
Upvotes: 3
Reputation: 1296
I dont know how to explain properly but ng-if adds a new scope to the element, his own scope, check this so question to see more details: what is the difference between ng-if and ng-show/ng-hide. I tried with ng-show and it worked the way you want:
ng-show="count > 0"
Hope it helps =)
Upvotes: 1