Reputation: 686
I'd like to animate an image swap in an angular 4 app. As the controller replaces the img src property the old image should fade away and the new appear.
In AngularJS this was possible by changing the opacity with ng-animate-swap. However, Angular 4 doesn't seem to support animate-swap. How can this be achieved without a swap trigger?
I've tried adding transitions from void to * and back for the src property but this doesn't work as expected. The first image is animated in, later the exchanges happen without animation.
@Component({
selector: 'app-play-card',
template: '<div (click)="loadImg()"><img [@fade]="imgsrc" src="{{ imgsrc }}" /></div>',
styleUrls: ['./play-card.component.css'],
animations: [
trigger('fade', [
transition('void => *', [
style({opacity: 0.1}),
animate(5000, style({opacity: 1}))
]),
transition('* => void', [
style({opacity: 0.9}),
animate(5000, style({opacity: 0}))
])
])
]
})
Upvotes: 3
Views: 11625
Reputation: 2503
If you are working with 2 images.... You could do something like this..
<mat-icon>
<img
[@fadeIn]
*ngIf="myBool"
src="assets/svg-icons/back.svg"
alt=""
/>
<img
[@fadeIn]
*ngIf="!myBool"
src="assets/svg-icons/close.svg"
alt=""
/>
</mat-icon>
And you will want to animate only the enter state otherwise for an instance both images will be shown side by side
trigger('fadeIn', [
transition(':enter', [style({ opacity: 0 }), animate(160)]),
// transition(':leave', [animate(160, style({ opacity: 0 }))]),
]),
You could work around and make the images absolute and then you can animate both the enter and leave state (Because this time the image will overlap each other)
Upvotes: 0
Reputation: 1
I did filter out as much as possible not to overload the code. I hope the code is simple enough for you to integrate it.
gallery.component.ts
:
import { Component, Input } from '@angular/core';
import { trigger, style, animate, transition } from '@angular/animations';
const animations = trigger('imgAnimation', [
transition(':enter', [
style({ opacity: 0 }),
animate('500ms', style({ opacity: 1 })),
]),
transition(':leave', [
animate('300ms', style({ opacity: 0 }))
])
]);
@Component({
selector: 'app-gallery',
templateUrl: './gallery.component.html',
styleUrls: [],
animations: [animations]
})
export class GalleryComponent {
@Input() images: string[];
index: number = 0;
imageIndex: number = 0;
onIncIndex(increment: number = 1) {
this.index = (this.index + this.images.length + increment) % this.images.length;
this.imageIndex = null;
}
onDone() {
this.imageIndex = this.index;
}
}
gallery.component.html
:
<picture>
<ng-container *ngFor="let img of images; index as i">
<img *ngIf="i === imageIndex"
@imgAnimation
(@imgAnimation.done)="onDone()"
[src]="img">
</ng-container>
</picture>
<div>
<button (click)="onIncIndex(-1)">Previous</button>
<button (click)="onIncIndex()">Next</button>
</div>
Upvotes: 0
Reputation: 3460
Here is how I did using Angular animations states:
animations.ts
import { trigger, style, animate, transition, state } from '@angular/animations';
export const fade = [
trigger('fade', [
state('in', style({ 'opacity': '1' })),
state('out', style({ 'opacity': '0' })),
transition('* <=> *', [
animate(1000)
])
])
];
app.component.html
<img [@fade]="state" (@fade.done)="onDone($event)" [src]="imageSource" width="500" (click)="onClick()" />
I used (@fade.done)
which is a feature of Angular animations that allows you to call a method once your animation is done.
Here, once the first animation has faded to have an opacity of 0, I changed the image path, and changed the animation state, to fade again and have the opacity value back to 1.
app.component.ts
export class AppComponent implements OnInit {
choice = 2;
state = 'in';
counter = 0;
enableAnimation = false;
imageSource = '';
imgSrc1 = 'firstPath';
imgSrc2 = 'secondPath';
ngOnInit() {
this.imageSource = this.imgSrc1;
}
onClick() {
this.enableAnimation = true;
this.counter = 0;
this.toggleState();
}
toggleImg() {
if (this.choice === 1) {
this.imageSource = this.imgSrc1;
this.choice = 2;
} else {
this.imageSource = this.imgSrc2;
this.choice = 1;
}
}
onDone($event) {
if (this.enableAnimation) {
if (this.counter === 1) {
this.toggleImg();
}
this.toggleState();
}
}
toggleState() {
if (this.counter < 2) {
this.state = this.state === 'in' ? 'out' : 'in';
this.counter++;
}
}
}
This is obviously a lot of code for a small animation though.
Here is a StackBlitz example I made for this : https://stackblitz.com/edit/angular-anim-fade-img
Upvotes: 7