Déjame explicarte un poco la funcionalidad. Mi objetivo es cuando el video se está reproduciendo, si un usuario hace clic en el video, se detendrá y entonces podría hacer algo en el camino. Mientras tanto, necesito detectar si un usuario está inactivo durante 30 segundos. Si es así, reanude automáticamente el video nuevamente.
Lo he implementado usando la funcionalidad setTimeout básica de javascript. Déjame compartir el código a continuación
@HostListener('window:click', ['$event']) onClick: (event) => { // stop the video this.activity = setTimeout(() => { /* resume */ } , 30000) } @HostListener('window:mousemove', ['$event']) onMouseMove: (event) => { clearTimeout(this.activity) this.activity = setTimeout(() => { /* resume */ } , 30000) } ¿Alguna sugerencia de cómo se puede resolver esto usando la forma RxJs ?
activity = new Subject<void>(); @HostListener('window:click', ['$event']) onClick(event: any) { // stop the video interval(30000).pipe(takeUntil(this.activity)).subscribe(() => { /* resume */ this.activity.next(); this.activity.complete(); }); } @HostListener('window:mousemove', ['$event']) onMouseMove(event: any) { this.activity.next(); this.activity.complete(); this.activity = new Subject<void>(); interval(30000).pipe(takeUntil(this.activity)).subscribe(() => { /* resume */ this.activity.next(); this.activity.complete(); }); }Esto es lo que se me ocurrió:
Corre fuera de la Zona Angular. No sobrecargará su aplicación con la detección de cambios cuando el mouse se esté moviendo. Activa la detección de cambios solo cuando el video se detiene o continúa.
import { DOCUMENT } from '@angular/common'; import { Inject, Injectable, NgZone } from '@angular/core'; import { BehaviorSubject, fromEvent, merge, Observable, of, Subject, } from 'rxjs'; import { distinctUntilChanged, mapTo, startWith, switchMapTo, debounceTime, takeUntil, } from 'rxjs/operators'; @Injectable({ providedIn: 'root' }) export class VideoService { private readonly onDestroy = new Subject<void>(); readonly isPlaying$: Observable<boolean> = new BehaviorSubject(true); constructor( @Inject(DOCUMENT) private readonly document: Document, private readonly ngZone: NgZone ) { // Run the whole logic outside of angular, so it won't burdent the app this.ngZone.runOutsideAngular(() => { fromEvent(this.document, 'click', { passive: true }) .pipe( // On every click we create a merge observable, and unsubscribe from the previous one if exists switchMapTo( // We merge two observables merge( // one that sets the playing to false instantly of(false), // Subscribe to the documents mousemove fromEvent(this.document, 'mousemove', { passive: true }).pipe( // we start the stream with a value, so after the clicking it will go back to playing without moving the cursor. startWith(null), // With debounceTime we wait for no mousemove debounceTime(1000), // All values are mapped to true mapTo(true) ) ) ), distinctUntilChanged(), takeUntil(this.onDestroy) ) .subscribe((value) => // when we get a different value run it in the zone, so Angular will know to run change detection. this.ngZone.run(() => { (this.isPlaying$ as BehaviorSubject<boolean>).next(value); }) ); }); } ngOnDestroy() { this.onDestroy.next(); this.onDestroy.complete(); } }Estoy interesado en otras soluciones, ya que la mía no parece ser simple. Siento que se puede hacer más simple también.