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