-
Notifications
You must be signed in to change notification settings - Fork 26.6k
Description
Which @angular/* package(s) are relevant/related to the feature request?
animations
Description
It is currently not possible to handle animation lifecycle events like (animate.enter) or (animate.leave) on the host element using @HostBinding() or @HostListener().
Please provide a way to host-bind or host-listen a callback function for these animation events so that custom animations can be run without adding template event bindings everywhere.
Why is this useful?
With GSAP (or any third-party animation lib), I currently have to manually bind AnimationCallbackEvent handlers in the component template for every instance:
<div (animate.enter)="animateEnter($event)" (animate.leave)="animateLeave($event)">
...
</div>
and inside component:
...
animateEnter(event: AnimationCallbackEvent) {
gsap.effects.fadeIn(event.target).eventCallback('onComplete', () => event.animationComplete());
}
animateEnter(event: AnimationCallbackEvent) {
gsap.effects.fadeOut(event.target).eventCallback('onComplete', () => event.animationComplete());
}
This results in repetitive boilerplate.
Now imagine a simple AnimateLeaveGsapDirective
:
@Directive({
selector: '[animateLeaveGsap]'
})
export class AnimateLeaveGsapDirective implements OnInit {
/** The name of GSAP effect to apply for animate.leave */
readonly animateLeaveGsap = input.required<string>();
@HostBinding('(animate.leave)')
animateLeave: Function;
// or
@HostListener('animate.leave', ['$event'])
onLeave(event: AnimationCallbackEvent) {
...
}
ngOnInit(): void {
const effectName = this.animateLeaveGsap();
const effect = gsap.effects[this.animateLeaveGsap()] as (targets: gsap.TweenTarget) => gsap.core.Tween;
if (!effect) {
console.warn('Error binding GSAP leave animation. Effect not found:', effectName);
return;
}
this.animateLeave = (event: AnimationCallbackEvent) => {
effect(event.target).eventCallback('onComplete', () => event.animationComplete());
}
}
}
Then templates become as simple as CSS-class-like bindings:
<div animateEnterGsap="fade-in" animateLeaveGsap="fade-out">
...
</div>
No more boilerplate.
Proposed solution
Allow directives/components to attach animation lifecycle handlers on the host via a decorator or host metadata, similar to DOM events:
@HostBinding('(animate.enter)')
animationCallbackFunction: (event: AnimationCallbackEvent) => void;
Alternatives considered
No good alternatives. The only current option is to bind (animate.enter) / (animate.leave) in every template where the component/directive is used, which scales poorly and scatters animation wiring across templates.