Last active
February 13, 2018 13:51
-
-
Save marcorinck/7c865115dca4e06f15d2a253e76d2f6a to your computer and use it in GitHub Desktop.
An example when you need dynamic properties inside of an angular animation and need to implement the animation in ts code and not in the animation DSL
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
<card (click)="clicked()"> | |
<card-content> | |
<card-title [ngStyle]="{'font-size': fontsize}">{{itemDetails.name}}</ion-card-title> | |
<icon [svgIcon]="itemDetails.icon" [style.height.px]="iconWidthHeight" | |
[style.width.px]="iconWidthHeight" ></icon> | |
</card-content> | |
</card> |
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
import {animate, AnimationBuilder, AnimationPlayer, style, OnChanges} from "@angular/animations"; | |
import {Component, ElementRef, HostBinding, Input} from "@angular/core"; | |
@Component({ | |
templateUrl: 'animated-item.component.html', | |
selector: 'animated-item', | |
}) | |
export class AnimatedItemComponent implements OnChanges { | |
itemPlayer: AnimationPlayer; | |
iconPlayer: AnimationPlayer; | |
titlePlayer: AnimationPlayer; | |
leftPosition: number; | |
topPosition: number; | |
fontsize: string; | |
iconWidthHeight = 0; | |
@Input() | |
itemDetails: MyCustomDetailClass; | |
@HostBinding("style.width.px") | |
width: number; | |
@HostBinding("style.height.px") | |
height: number; | |
constructor(private el: ElementRef, private animationBuiler: AnimationBuilder) {} | |
animate() { | |
//... calculate Heights,widths and all other parameters, details omitted bc clarity | |
this.destroyPlayers(); | |
const itemAnimation = this.createItemAnimation(width, height, leftPosition, topPosition); | |
const iconAnimation = this.createIconAnimation(iconWidthHeight); | |
const titleAnimation = this.createTitleAnimation(fontsize); | |
this.itemPlayer = itemAnimation.create(this.el.nativeElement); | |
this.iconPlayer = iconAnimation.create(this.icon.nativeElement); | |
this.titlePlayer = titleAnimation.create(this.title.getNativeElement()); | |
this.itemPlayer.play(); | |
this.iconPlayer.play(); | |
this.titlePlayer.play(); | |
this.itemPlayer.onDone(() => { | |
//a CustomEvent not only bubbles to the immediate (angular) parent element but can bubble up to the root element | |
//this event happens when the animation is done | |
const ev = new CustomEvent("animationDone", {bubbles: true}); | |
this.el.nativeElement.dispatchEvent(ev); | |
}) | |
} | |
clicked() { | |
//a CustomEvent not only bubbles to the immediate (angular) parent element but can bubble up to the root element | |
//this event happens when the component/item is clicked and triggers the animatin (implementation detail) | |
const ev = new Event("wasClicked", {bubbles: true, cancelable: true}); | |
this.el.nativeElement.dispatchEvent(ev); | |
} | |
ngOnChanges() { | |
this.animate(); | |
} | |
private createTitleAnimation(fontsize: string) { | |
return this.animationBuiler.build([ | |
style({ | |
"font-size": this.fontsize, | |
}), | |
animate(`500ms ${this.delay}ms cubic-bezier(.35, 0, .25, 1)`, style({ | |
"font-size": fontsize | |
})) | |
]); | |
} | |
private createIconAnimation(iconWidthHeight: number) { | |
return this.animationBuiler.build([ | |
style({ | |
width: this.iconWidthHeight, | |
height: this.iconWidthHeight, | |
}), | |
animate(`500ms ${this.delay}ms cubic-bezier(.35, 0, .25, 1)`, style({ | |
width: iconWidthHeight + "px", | |
height: iconWidthHeight + "px", | |
})) | |
]); | |
} | |
private createItemAnimation(width: number, height: number, leftPosition: number, topPosition: number) { | |
return this.animationBuiler.build([ | |
style({ | |
width: this.width, | |
height: this.height, | |
transform: `translate3d(${this.leftPosition}px, ${this.topPosition}px, 0)` | |
}), | |
animate(`500ms ${this.delay}ms cubic-bezier(.35, 0, .25, 1)`, style({ | |
width: width + "px", | |
height: height + "px", | |
transform: `translate3d(${leftPosition}px, ${topPosition}px, 0)` | |
})) | |
]); | |
} | |
//when there is already an animation running you have to stop/destroy it first, before you create a new one | |
private destroyPlayers() { | |
if (this.itemPlayer) { | |
this.itemPlayer.destroy(); | |
} | |
if (this.iconPlayer) { | |
this.iconPlayer.destroy(); | |
} | |
if (this.titlePlayer) { | |
this.titlePlayer.destroy(); | |
} | |
} | |
} |
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
<animated-item *ngFor="let item of items; let i = index" [itemDetails]="item" | |
(wasClicked)="selectItemSoAnimationWillBeTriggered(item)"> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment