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

ngAnimate & ngClass - Does not remove a class that is still animating #14582

Closed
thetrevdev opened this issue May 10, 2016 · 2 comments · Fixed by #14760
Closed

ngAnimate & ngClass - Does not remove a class that is still animating #14582

thetrevdev opened this issue May 10, 2016 · 2 comments · Fixed by #14760

Comments

@thetrevdev
Copy link

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
http://plnkr.co/edit/wsVFlxSJFCslfV9Hossg?p=preview
When a class is added via ngClass then removed too quickly we end up in a state where still have the class on the element.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.
http://plnkr.co/edit/wsVFlxSJFCslfV9Hossg?p=preview
*This is a race condition. This plunker is failing over 90% of the time though,

What is the expected behavior?
The falsy ngClass is removed

What is the motivation / use case for changing the behavior?

Which versions of Angular, and which browser / OS are affected by this issue? Did this work in previous versions of Angular? Please also test with the latest stable and snapshot (https://code.angularjs.org/snapshot/) versions.
Plnkr was failing in 1.4 -> 1.5.5

Other information (e.g. stacktraces, related issues, suggestions how to fix)
Definitely related to ngAnimate as the issue goes away when its not used.
Likely related to the intermediate animate states. In the plunker above we would see .background-add on the element at the time we try to remove .background
This appears to only happen when the new ngClass state is also adding classes.

@Narretz
Copy link
Contributor

Narretz commented May 12, 2016

Thanks for the report. I can reproduce the bug. However, I only see the bug when the classes are initially set in rapid succession. I also only see this behavior when there's 15 ms or less between each update. Such short intervals are pretty unusual, under which circumstances is this happening for you?

@thetrevdev
Copy link
Author

It happens pretty frequently for us.
We have an ngClass that would look like { classA: someBool, classB: !someBool }
someBool is getting updated via an api call. It would appear that the api call is coming in right after our element compiles.

Narretz added a commit to Narretz/angular.js that referenced this issue Jun 13, 2016
…with requestAnimationFrame

The following case can happen when ngClass updates an element's classes in very quick order in the following way:

- First animation adds class "a"
- A digest passes, but "a" is not yet added to the element
- Second animation adds class "b"
- No digest passes, and "a" is still not added to the element,
  because requestAnimationFrame hasn't been flushed yet
- Third animation removes class "a"
- the third animation gets merged into the second animation

Before this change:

- Because the element doesn't have class "a" yet, ngAnimate
resolves that it cannot remove class "a". However,
the first animation is still running, and finally adds "a"

After this change:

- ngAnimate reacts to the temporary class "add-a", which indicates
that "a" is about to be added and decides that "a" can be removed
after all.

This is a very rare case where setting the element's class
is not fast enough, and subsequent animations operate on incorrect assumptions.

"In the wild", this is caused by rapidly updating ngClass,
which uses inidvidual addClass and removeClass calls when both operations happen in a single digest.

Fixes angular#14582
Narretz added a commit that referenced this issue Jun 22, 2016
…with requestAnimationFrame

Also affects the reverse case, adding a class that is scheduled to be removed with rAF.

The following case can happen when ngClass updates an element's classes in very quick order in the following way:

- First animation adds class "a"
- A digest passes, but "a" is not yet added to the element
- Second animation adds class "b"
- No digest passes, and "a" is still not added to the element,
  because requestAnimationFrame hasn't been flushed yet
- Third animation removes class "a"
- the third animation gets merged into the second animation

Before this change:

- Because the element doesn't have class "a" yet, ngAnimate
resolves that it cannot remove class "a". However,
the first animation is still running, and finally adds "a"

After this change:

- ngAnimate reacts to the temporary class "add-a", which indicates
that "a" is about to be added and decides that "a" can be removed
after all.

This is a very rare case where setting the element's class
is not fast enough, and subsequent animations operate on incorrect assumptions.

"In the wild", this is caused by rapidly updating ngClass,
which uses inidvidual addClass and removeClass calls when both operations happen in a single digest.

Fixes #14582
PR  (#14760)
Narretz added a commit that referenced this issue Jun 23, 2016
…with requestAnimationFrame

Also affects the reverse case, adding a class that is scheduled to be removed with rAF.

The following case can happen when ngClass updates an element's classes in very quick order in the following way:

- First animation adds class "a"
- A digest passes, but "a" is not yet added to the element
- Second animation adds class "b"
- No digest passes, and "a" is still not added to the element,
  because requestAnimationFrame hasn't been flushed yet
- Third animation removes class "a"
- the third animation gets merged into the second animation

Before this change:

- Because the element doesn't have class "a" yet, ngAnimate
resolves that it cannot remove class "a". However,
the first animation is still running, and finally adds "a"

After this change:

- ngAnimate reacts to the temporary class "add-a", which indicates
that "a" is about to be added and decides that "a" can be removed
after all.

This is a very rare case where setting the element's class
is not fast enough, and subsequent animations operate on incorrect assumptions.

"In the wild", this is caused by rapidly updating ngClass,
which uses inidvidual addClass and removeClass calls when both operations happen in a single digest.

Fixes #14582
PR  (#14760)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants