Skip to content

feat(core): add enter and leave animation instructions #62682

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

thePunderWoman
Copy link
Contributor

This adds the instructions to support enter and leave animations on nodes.

Does this PR introduce a breaking change?

  • Yes
  • No

@thePunderWoman thePunderWoman added area: core Issues related to the framework runtime target: minor This PR is targeted for the next minor release labels Jul 17, 2025
@ngbot ngbot bot added this to the Backlog milestone Jul 17, 2025
@angular-robot angular-robot bot added the detected: feature PR contains a feature commit label Jul 17, 2025
@thePunderWoman thePunderWoman force-pushed the animate-instructions branch 2 times, most recently from 843db01 to 46066a1 Compare July 17, 2025 11:04
@pullapprove pullapprove bot requested review from crisbeto, kirjs and mmalerba July 17, 2025 11:04
@thePunderWoman thePunderWoman force-pushed the animate-instructions branch 2 times, most recently from 3c38d4a to 056dcb3 Compare July 17, 2025 11:53
Copy link

github-actions bot commented Jul 17, 2025

Deployed adev-preview for 342ed87 to: https://ng-dev-previews-fw--pr-angular-angular-62682-adev-prev-yvy73xs1.web.app

Note: As new commits are pushed to this pull request, this link is updated after the preview is rebuilt.

animate(el: Element, removeFn: Function): void {
if (!this.outElements.has(el)) return;
const details = this.outElements.get(el)!;
const timeout = setTimeout(() => removeFn(), 4000);
Copy link
Member

@JeanMeche JeanMeche Jul 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4000 feels like a magic number here. Can we use a named a named constant and/or have a comment on why this value. (Would animations longer than 4s just get removed after ther 4s ?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Certainly. I've added a const and associated comment about why 4 seconds.

Copy link
Contributor Author

@thePunderWoman thePunderWoman Jul 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also to quickly answer your question here, if you're using an animation function (rather than classes) for animate.leave, you are required to call the complete function to tell the framework when to remove the element. The feedback on the RFC was to have a timeout for safety, and so I went with the same timeout duration as cross document view transitions. So after a 4 second timeout, the element gets removed. If your animation is done before that, no issues.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if we can have an injection token that configures it? And the default would still be 4s.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can keep it like this for now, but we should probably output a dev-mode warning for cases when timeout is triggered (for ex. for cases when the "done" callback is never invoked). That can help to surface this situations and we can see if there are cases when the timeout needs to be adjusted.

A couple additional thoughts:

  • This can be done in a followup PR
  • We should consider cases when those warnings are produced for elements inside of @for loops and avoid spamming console with those warnings

@thePunderWoman thePunderWoman force-pushed the animate-instructions branch 2 times, most recently from 72ef660 to 4d2fc63 Compare July 17, 2025 14:34
@thePunderWoman thePunderWoman added the action: review The PR is still awaiting reviews from at least one requested reviewer label Jul 17, 2025
@thePunderWoman thePunderWoman force-pushed the animate-instructions branch 2 times, most recently from 277e2bf to e6569a6 Compare July 18, 2025 12:25
@thePunderWoman
Copy link
Contributor Author

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for animate.enter and animate.leave instructions for animations on nodes. The changes include new public APIs like AnimationCallbackEvent, AnimationFunction, and ANIMATIONS_DISABLED, a new ElementRegistry service to manage animations for leaving elements, and the core implementation in the rendering instructions. The changes are well-supported by a comprehensive suite of acceptance tests. I've identified a couple of potential issues in packages/core/src/animation.ts and packages/core/src/render3/instructions/animation.ts. Please see my detailed comments.

const tNode = getCurrentTNode()!;
const nativeElement = getNativeByTNode(tNode, lView) as HTMLElement;

if ((nativeElement as Node).nodeType !== Node.ELEMENT_NODE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious what'd be an example of such usage (I believe host bindings might be in that category)? If we come up with an example, we can see what'd be the best way to handle it and whether the code should be at compile-time (preferable, if possible) or at runtime.

animate(el: Element, removeFn: Function): void {
if (!this.outElements.has(el)) return;
const details = this.outElements.get(el)!;
const timeout = setTimeout(() => removeFn(), 4000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can keep it like this for now, but we should probably output a dev-mode warning for cases when timeout is triggered (for ex. for cases when the "done" callback is never invoked). That can help to surface this situations and we can see if there are cases when the timeout needs to be adjusted.

A couple additional thoughts:

  • This can be done in a followup PR
  • We should consider cases when those warnings are produced for elements inside of @for loops and avoid spamming console with those warnings

This adds the instructions to support enter and leave animations on nodes.
@angular-robot angular-robot bot added the area: compiler Issues related to `ngc`, Angular's template compiler label Jul 21, 2025
@thePunderWoman thePunderWoman force-pushed the animate-instructions branch 3 times, most recently from 9b3ded6 to 45211a4 Compare July 21, 2025 17:39
Copy link
Contributor

@AndrewKushnir AndrewKushnir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thePunderWoman thanks for making the ElementRegistry tree-shakable 👍

I've left a few minor comments and I also wanted to propose that we check whether we can use areAnimationSupported to exit a bit earlier (e.g. in the main instructions vs inside of util functions later).

@thePunderWoman thePunderWoman force-pushed the animate-instructions branch 2 times, most recently from b1822ef to 0d62304 Compare July 22, 2025 10:17
// The animations will only be disabled in a test environment, and adding a microtask here
// will allow the tests to be able to tick forward to resolve the next phase of animation
// in their tests.
Promise.resolve().then(() => {
Copy link
Contributor

@atscott atscott Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should run outside the Angular zone too, right? Unless the intent is to trigger change detection here for applications using NgZone. This would differ from zoneless applications in that case unless we create some trigger for those as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually test only. It's intended for people to be able to tick forward in tests and see the classes get added / removed. The token that disables animations is currently in the core/testing package and in a follow up will be only provided in the animations test utility. So it should be ok here.

Copy link
Contributor

@atscott atscott Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So to be fair, this will cause tests to behave differently than production (thanks NgZone...) by causing an extra change detection. For better or for worse (definitely for worse), we have observed tests trying to count CD cycles. There could be other cases that this affects as well. For example, the listener callbacks, which execute outside the Angular zone, may make changes to application state. If this isn't done with ngZone.run, markForCheck, etc. production code will not know to trigger change detection but the test code will due to the promise here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's always going to be the case, unfortunately. getAnimations does not exist on DOM nodes in a unit test environment. So no animations can actually happen in that case, meaning for those types of tests users have to disable animations. This at least gives them the option to see the classes being added and removed after a tick. So they can verify that the change at least happened. The acceptance tests for this are actually skipping the node environment for that reason.

If you're running tests in a browser, you would not disable animations. So in that case, this code wouldn't be reachable, meaning animations would behave as normal.

@pullapprove pullapprove bot requested a review from atscott July 22, 2025 16:46
@thePunderWoman thePunderWoman force-pushed the animate-instructions branch 2 times, most recently from 0fb85a4 to 25a89cb Compare July 22, 2025 17:08
Copy link
Contributor

@AndrewKushnir AndrewKushnir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks @thePunderWoman 👍

Just left some minor comments, but none of them are blocking. Let's discuss the testing story as a followup.

Comment on lines +497 to +503
if (animationsDisabled) {
// add a microtask for test environments to be able to see classes
// were added, then removed.
Promise.resolve().then(() => {
finalRemoveFn();
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker for this PR, but we'd probably need to discuss the testing story. I think that relying on the presence of classes may be a bit brittle (especially in case we need to emulate certain timing) and we may instead introduce a utility function to check if a given element was processed by the animation subsystem. That would also allow us to remove this special handling.

This creates a feature to detect usages of animate.leave and only enables the element removal registry when necessary
Copy link
Member

@crisbeto crisbeto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed-for: public-api

Copy link
Member

@JeanMeche JeanMeche left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed-for: public-api

@thePunderWoman thePunderWoman added action: merge The PR is ready for merge by the caretaker and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Jul 23, 2025
@kirjs
Copy link
Contributor

kirjs commented Jul 23, 2025

This PR was merged into the repository by commit 882522c.

The changes were merged into the following branches: main

@kirjs kirjs closed this in 6b1f4b9 Jul 23, 2025
kirjs pushed a commit that referenced this pull request Jul 23, 2025
This creates a feature to detect usages of animate.leave and only enables the element removal registry when necessary

PR Close #62682
PowerKiKi referenced this pull request in unil-lettres/dilps-tiresias Jul 25, 2025
If `showHideRelatedCards` is refactored into native CSS, then the
package `@angular/animations` could be dropped entirely.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
action: merge The PR is ready for merge by the caretaker adev: preview area: compiler Issues related to `ngc`, Angular's template compiler area: core Issues related to the framework runtime detected: feature PR contains a feature commit target: minor This PR is targeted for the next minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy