I want to manually perform page transitions in my Angular2 app. So what I have done so far is produced a service that I call from a Component that deals with navigation. When you click on some link, or icon or whatever I call the AnimationService goTo
method. This receives a URL and pushes to an Observable stream / subject. Here is the service so far:
@Injectable()
export class AnimationService {
// should you be a directive?
animationStream: Subject<string> = new Subject<string>();
animationStreamEnd:Subject<string> = new Subject<string>()
constructor() {
// this is to listen for when it is time to navigate to whereever?
this.animationStreamEnd.subscribe(resp => {
// redirect the url / app here
this.router.go(resp);
});
}
goTo(url:string): void {
// so, broadcast down to trigger the css animation...
this.animationStream.next(url);
}
}
the content that I wish to animate has a ngClass
condition in it's HTML template like so [ngClass]="{'animate-left': applyTransitionClass}"
, it looks something like this
<div class="gridClass" [ngClass]="{'animate-left': applyTransitionClass}">
<div class="gridRow">
<route-view></route-view>
</div>
</div>
</div>
and in it's component I have the following code
export class AnotherComponent {
constructor(private animationService: AnimationService) {
public applyTransitionClass: boolean = false;
this.animationService.animationStream.subscribe(resp => {
// resp is a url...
// apply a css class... when that is done we need to broadcast the thing is done...
this.applyTransitionClass = true;
// here I want to listen for when the animation end (it is only 1 second) and tell the animationService to now navigate to wherever
this.animationService.animationStreamEnd.next(resp);
});
}
You can see where I subscribe to the Observable and how I change the value that triggers the css animation. Now within the Component I wish to listen for the end of the css class I have just triggered then let the AnimationService know this has happened by pushing to the animationStreamEnd. However I don't know how to get hold of the animation end event (like "transitionend","oTransitionEnd","transitionend","webkitTransitionEnd"
). I know I could just set a 1 second delay but I want this to use Observables.
I know I haven't explained myself well, I will amend the question should I need to clarify the requirement. Thanks in advance.
component-view:
<div (transitionend)="transitionEnd($event)">
...
</div>
component-code:
transitionEnd(e: Event){
alert('no way, that easy?');
}
This is how I am doing it:
//this.isIn = false;
this.renderer.invokeElementMethod(this.elementRef.nativeElement, 'addEventListener', ['animationend', (e) => {
console.log(e);
}]);
this.renderer.invokeElementMethod(this.elementRef.nativeElement, 'addEventListener', ['transitionend', (e) => {
console.log(e);
}]);
The Angular2 animation module got callbacks implemented just before 2.0.0 final.
https://angular.io/docs/ts/latest/guide/animations.html#!#animation-callbacks
template: ` <ul> <li *ngFor="let hero of heroes" (@flyInOut.start)="animationStarted($event)" (@flyInOut.done)="animationDone($event)" [@flyInOut]="'in'"> {{hero.name}} </li> </ul> `,
You can now use the @HostListener decorator to listen to events on the host element.
For your case we can listen to the transitionstart
and transitionend
events:
@Component({
selector: 'app-hello-world',
template: 'Hello world',
})
export class HelloWorldComponent {
@HostListener('transitionstart', ['$event'])
onTransitionStart(event) {
console.log('Transition started:', event);
}
@HostListener('transitionend', ['$event'])
onTransitionEnd(event) {
console.log('Transition ended:', event);
}
}
Note that injecting the event (second parameter) is optional.
The same can be achieved using RXJS by listenening to events on a target element, like so:
const element = this.elementRef.nativeElement;
fromEvent(element, 'transitionstart').subscribe((event) => {
console.log('Started transition:', event);
});
Here is a cool little abstraction to merge multiple events:
merge(
fromEvent(element, 'transitionstart').pipe(mapTo('start')),
fromEvent(element, 'transitionend').pipe(mapTo('end'))
).subscribe(phase => {
console.log('Transition phase:', phase);
});
Don't forget to unsubscribe when you're done, we don't want memory leaks.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With