Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

ngIf directive element not removed on falsy #5241

Closed
whyvez opened this issue Dec 3, 2013 · 12 comments
Closed

ngIf directive element not removed on falsy #5241

whyvez opened this issue Dec 3, 2013 · 12 comments

Comments

@whyvez
Copy link
Contributor

whyvez commented Dec 3, 2013

AngularJS version 1.2.2 in Chrome Version 31.0.1650.57 on OSX Maverick

I haven't gotten down to the exact source yet but just adding this here as a note for the animation team. I had a situation today where the animation classes where being applied to an ngIf directive even though I had no animation set on it either via css or js. To complicate things even more the element with the ngIf never got removed from the DOM even if the ngIf expression resoled to false. The root of this issue was a vanilla css transition (not via ngAnimate) that was set on the element. Seems like the the leave hung at step 7 (from docs) where it was waiting for the transition to complete and got hung up.

Summary:

  1. still can't explain why the $animte service got triggered in this element... not sure how each animation is registered with the service solely on css classes. Removed any classes I had set on the element to make sure there was no collision but was still an issue.
  2. issue where the ngIf got hung and never finished removing the element from the DOM because there was a css transition set on the element. Once I removed the culprit transition declaration everything worked fine.

DOM structure example: (scope.currentPage is an int)

<div>
    <ul ng-repeat="page in pages">
        <li ng-repeat="item in page" ng-if="$parent.$index == currentPage">item</li>
    <ul>
</div>

@ghost ghost assigned matsko Dec 4, 2013
@matsko
Copy link
Contributor

matsko commented Dec 4, 2013

Hey Yves. Can you provide a plunkr to this? You may have an inherited transition occurring on the element which is causing the animation to trigger.

@matsko
Copy link
Contributor

matsko commented Dec 16, 2013

I put together a demo based on what you had there, any idea what I'm missing? Looks fine to me.

http://plnkr.co/edit/ZEe7V8TH1o7mGJevdMcE?p=preview

@whyvez
Copy link
Contributor Author

whyvez commented Dec 16, 2013

Apologies for the tardiness. Will look at this today.

@whyvez
Copy link
Contributor Author

whyvez commented Dec 16, 2013

Yes this plunkr is a good start. My code is essentially an infinite scroller implemented with the ng-if directive. It adds/removes list item based on position i.e. visible or not. I'm using iScroll to manage the safari IOS scroll quirks. Tried creating a plunkr when I first reported this issue but had difficulties getting iScroll working. I will update your plunkr with the specifics of my implementation later today. A+

@matsko
Copy link
Contributor

matsko commented Dec 16, 2013

@whyvez sounds great.

@whyvez
Copy link
Contributor Author

whyvez commented Dec 17, 2013

@matsko Encountered a similar issue once again this AM. Here is the plunker.

  1. Clicking on loading shows the spinner.
  2. Clicking on done should remove the spinner but it doesn't and ng-animate "hiding" classes are set on the element but it is never removed. (! the issue !)
  3. Clicking on loading again will re-insert another element. (from the docs this is the indented behaviour).

@whyvez
Copy link
Contributor Author

whyvez commented Dec 17, 2013

Same with angular v1.2.5: plunker

@matsko
Copy link
Contributor

matsko commented Dec 17, 2013

OK great. This is exactly what I need. Working on a fix. Thanks so much for putting together the plunkr.

@matsko
Copy link
Contributor

matsko commented Dec 17, 2013

Alright I found a solution. Basically you have an infinite animation going on and when ngAnimate runs it thinks that the keyframe animation applies to the enter and leave operations (that's why the animation restarts on leave). Normally it would run for a few seconds (3 seconds in your example) and then close off and then perform the leave operation. But in this case since the animation is infinite, ngAnimate will wait for it indefinitely (since CSS events are used to manage the animation).

With 1.2.6, there is a fix which does a hard close on all animations after 150% of the max duration of the animation passing. So with your example, if you click on loading and then done and wait 4.5 seconds (3 x 1.5 == 4.5 seconds) then it will close automatically.

(click on loading and done and then wait 5 seconds).
http://plnkr.co/edit/CHKb4ptKRJyK8DNlz100?p=preview

This can get to be annoying sometimes and your users will definitely see it as buggy, so to avoid having a hanging animation (even for 4.5 seconds), just override the .ng-animate class on it to tell ngAnimate not to animate on the enter, move, leave, addClass, removeClass animations.

.loading-indicator.ng-animate {
   -webkit-animation: none 0s;
   animation: none 0s;
}

This will skip the enter / leave animations for keyframe animations (since you're using -webkit-animation and animation). You only really need to do this if you have an infinite animation going on and you want to avoid waiting for the animation to close itself off.

http://plnkr.co/edit/sZVFyZibHrWBSNkoQFDv?p=preview

You can also mix and match transitions together into it so you can still have your infinite animation, but with a nice fade in fade out effect using CSS transitions. This may disguise the hanging animation until the 4.5 second timeout kicks in, but it's just an alternative if you want to mix transitions and keyframe animations together.

http://plnkr.co/edit/ypcgeMxGZNUfPLinhOxz?p=preview

I'll close this issue once: #5403 is in.

Thanks Yves.

matsko added a commit to matsko/angular.js that referenced this issue Dec 17, 2013
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
Closes angular#5241
Closes angular#5405
@whyvez
Copy link
Contributor Author

whyvez commented Dec 17, 2013

Although this explains this last circumstance it doesn't explain my original issue which did not have an infinite animation or keyframe animations. I will try and replicate the original issue with the latest version of angular with my code and if I can I will create another plunkr.

@whyvez
Copy link
Contributor Author

whyvez commented Dec 17, 2013

I can confirm that your workaround mentioned above fixed my issue re: infinite animation. Thanks! More soon re: original issue.

@whyvez
Copy link
Contributor Author

whyvez commented Dec 17, 2013

Just found another situation which more closely matches my original issue. I have a suspicion it might be related to iScroll (see screenshot below) Looks like it applies styles directly on the element. Any ideas? Since I had some Issues getting iScroll to work in plunkr I could create a simple app if you require. Let me know.

screen shot 2013-12-17 at 9 03 31 am

matsko added a commit to matsko/angular.js that referenced this issue Dec 19, 2013
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
Closes angular#5241
Closes angular#5405
@matsko matsko closed this as completed in 54637a3 Dec 19, 2013
jamesdaily pushed a commit to jamesdaily/angular.js that referenced this issue Jan 27, 2014
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
Closes angular#5241
Closes angular#5405
jamesdaily pushed a commit to jamesdaily/angular.js that referenced this issue Jan 27, 2014
…y to close transitions

With ngAnimate, CSS transitions, that are not properlty triggered, are forceably closed off
by appling a fallback property. The fallback property approach works, however, its styling
itself may effect CSS inheritance or cause the element to render improperly. Therefore, its
best to stick to using a scheduled timeout to run sometime after the highest animation time
has passed.

Closes angular#5255
Closes angular#5241
Closes angular#5405
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants