Repository navigation
fix(compiler): compile animate.enter and animate.leave listeners to the animation instructions - #597
Merged
Brooooooklyn merged 3 commits intoOct 22, 2026
Conversation
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
…he animation instructions
Template listeners compiled to ɵɵsyntheticHostListener("@animate.enter.start", ...), a legacy animation listener, and host listeners to ɵɵlistener("animate.leave", ...), a DOM event that never fires. Create AnimationListenerOp for these events, as Angular's ingest does, and reify it to the enter/leave listener instructions.
A static animate.enter / animate.leave host attribute was dropped because host reify ignored AnimationString ops; emit ɵɵanimateEnter / ɵɵanimateLeave for it.
GabeSilvaDev
force-pushed
the
fix/animate-event-listeners
branch
from
October 21, 2026 11:46
98db00a to
b323642
Compare
…efix and dotted names
- `(animate.enter)` / `(animate.leave)` on an explicit `<ng-template>` stays a
plain listener with a consts entry, as Angular's `ingestTemplateBindings` does.
- `on-animate.enter` is an animation event, like `(animate.enter)`.
- The handler name drops only the first dot of the event name, like
`name.replace('.', '')`.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Member
|
@codex review |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
(animate.enter)and(animate.leave)listeners compile to the wrong instruction, so the handler never runs. For(animate.leave)that also means the element is removed right away instead of when the handler callsanimationComplete().OXC on
main:ngc, and OXC with this change:
The gaps were in these places:
pipeline/ingest.rsAnimationListenerOpexisted in the IR, and naming and reify handled it, but nothing created it. A comment iningest_listener_ownednoted thatParsedEventType::Animation"should be dispatched to AnimationListenerOp by a separate template-path fix". Template and host events of that type now create it, as iningestElementEvents/ingestHostEvent. The last handler expression becomes areturnstatement (makeListenerHandlerOps).directive/compiler.rs,component/transform.rsanimate.are nowParsedEventType::Animation, as in the binding parser's_parseRegularEvent. They wereRegularbefore. As upstream does, the check runs on the name before anywindow:/document:/body:target is split off.reify/statements/misc.rscreate_animation_listener_stmtemittedɵɵsyntheticHostListener("@name.start"/"@name.done", fn). It now emitsɵɵanimateEnterListener(fn)/ɵɵanimateLeaveListener(fn), likeanimationListenerininstruction.ts.reify/mod.rsAnimationStringops, so a staticanimate.enter/animate.leavehost attribute was converted and then dropped. It now emitsɵɵanimateEnter/ɵɵanimateLeave, as the template reify already does.The instructions exist since Angular 20.2.0, the release that added
animate.enter/animate.leave. Like the existingɵɵanimateEnter/ɵɵanimateLeaveemit, they are not gated on the Angular version.Follow-up commit (b007071)
A review against ngc 22.2.2 found three more cases:
<ng-template (animate.leave)="...">ɵɵanimateLeaveListener(...), no consts entryɵɵdomListener("animate.leave", ...)+[3, "animate.leave"], asingestTemplateBindingsdoes<div on-animate.enter="...">ɵɵdomListener("animate.enter", ...)ɵɵanimateEnterListener(...)(animate.enter.x)handler name..._animateenterx_0_listener..._animateenter_x_0_listener(only the first dot is dropped, likename.replace('.', ''))Tests
(animate.enter)listener;(animate.leave)listener with several statements next to a staticanimate.leave;(animate.leave)listener with a static hostanimate.enter;on-animate.enter;(animate.leave)on an<ng-template>.animations/animate-listener.fixture.ts. The four from the first commit fail onmain. The two new ones coveron-animate.enterand<ng-template>. All six match ngc 22.2.2; the only diff left is theɵsetClassDebugInfopath, already listed inknown-differences.ts.main:cargo test -p oxc_angular_compiler --all-features: 3484 passed;pnpm compare --fixtures: 1161 fixtures, 0 mismatches;pnpm test: 376 passed;pnpm checkpasses.One difference is left, and it was already there before this change: when an element has both a static
animate.enterand a bound[animate.leave], ngc emitsɵɵanimateLeavebeforeɵɵanimateEnterand OXC emits them the other way round. Both register on the same element in the creation pass, so behavior is the same. I left it out of this PR.Not in this PR (already wrong on
main; this PR does not touch those paths):[animate.leave]/@HostBinding('animate.enter')still emitsɵɵdomProperty, where ngc emitsɵɵanimateLeave(fn)in the create block;animate.enterintohostAttrs.