Re-activate video playback after 30 seconds of user inactivity (using RxJs)

My intention is to provide a brief explanation of the functionality I am looking for. Essentially, when a video is playing, I want it to pause if a user clicks on it, allowing them to do something else. Then, after 30 seconds of idle time, I need the video to automatically resume.

To achieve this, I have utilized basic JavaScript's setTimeout functionality. You can see the code snippet below:

@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)
}

Any suggestions on how this could be accomplished using the RxJs approach?

Answer №1

interaction = new Subject<void>();

@HostListener('window:click', ['$event'])
handleClick(event: any) {
    // stop the video
    interval(30000).pipe(takeUntil(this.interaction)).subscribe(() => {
        /* resume */
        this.interaction.next();
        this.interaction.complete();
    });
}


@HostListener('window:mousemove', ['$event'])
handleMouseMove(event: any) {
    this.interaction.next();
    this.interaction.complete();

    this.interaction = new Subject<void>();

    interval(30000).pipe(takeUntil(this.interaction)).subscribe(() => {
        /* resume */
        this.interaction.next();
        this.interaction.complete();
    });
}

Answer №2

Here is the solution I have devised:

This code runs outside of the Angular Zone to avoid taxing your application with unnecessary change detection events while the mouse is in motion. It will only trigger a change detection event when the video playback stops or resumes.

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
  ) {
    // Executing the entire logic outside of Angular for minimal impact on app performance
    this.ngZone.runOutsideAngular(() => {
      fromEvent(this.document, 'click', { passive: true })
        .pipe(
          switchMapTo(
            merge(
              of(false),
              fromEvent(this.document, 'mousemove', { passive: true }).pipe(
                startWith(null),
                debounceTime(1000),
                mapTo(true)
              )
            )
          ),
          distinctUntilChanged(),
          takeUntil(this.onDestroy)
        )
        .subscribe((value) =>
          this.ngZone.run(() => {
            (this.isPlaying$ as BehaviorSubject<boolean>).next(value);
          })
        );
    });
  }

  ngOnDestroy() {
    this.onDestroy.next();
    this.onDestroy.complete();
  }
}

View live demo here!

I am open to exploring alternative solutions, as I believe there may be simpler approaches that have yet to be considered.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Instructions for making a crossword-inspired grid using a high quantity of divs or alternative elements

I am looking to create a grid on the screen of a web browser or mobile device, with each grid item containing just one letter. It's similar to a crossword puzzle, but taking up most of the screen. I've tried using divs for this purpose, but it se ...

The issue with THREE.js ORBITCONTROLLS not responding to changes in mouse button settings is causing inconvenience

Hey there, currently working on a project using THREE.js and I've run into an issue with my .mouseButtons functionality. var controls = new THREE.OrbitControls( camera, renderer.domElement ); controls.target.set( 0, 25, 0 ); c ...

React Weather App experiencing issues with prop communication and updating variables

My innovative weather app allows users to input custom longitude and latitude coordinates. Once the coordinates are received, they are passed as props to a child component where they are used in an API call to fetch data for that specific area. While ever ...

Include a character in a tube using Angular

Hey everyone, I have a pipe that currently returns each word with the first letter uppercase and the rest lowercase. It also removes any non-English characters from the value. I'm trying to figure out how to add the ':' character so it will ...

Exploring the capabilities of multiple nested controllers in AngularJS

I am facing a challenge that I haven't been able to find a solution for online. My search form includes multiple instances of a common controller used for typeahead/autocomplete searches. Each controller is set up with different parameters for search ...

Tips for expanding a script that relocates a logo into a navigation consisting of several unordered lists

I recently implemented a jQuery script to center a logo within my main navigation bar only when the screen width is above 980 pixels. It was working perfectly fine with a single unordered list, but as soon as I added more unordered lists within the nav, it ...

Testing Ajax code encounters error

Currently, I am running a code test with Jasmine and setting up a mock object for the ajax method. spyOn($,'ajax').and.callFake(function(e){ console.log("is hitting"); }) In order to test the code snippet below: $.ajax({ url: Ap ...

Using Typeof in an IF statement is successful, but attempting to use ELSE with the same

My goal is to create a JavaScript variable called str. In case the ID idofnet doesn't exist, I would like to prompt the user for a value to assign to str. However, if idofnet does exist, then I want to retrieve its value and assign it to str. This is ...

Ways to stop CKEDITOR from automatically saving textarea or contenteditable content

I've integrated the CKEDITOR plugin for a format toolbar feature on my web application. It seems that the message shown above is a default one provided by CKEDITOR. My goal is to have users start with a blank textarea every time they visit the page, ...

What is the most efficient way to restrict multiple input fields, each using v-model, to only accept numeric values in Vue.js without duplicating code for every input field?

I have several input fields in Vue.js that I want to restrict to only accept numbers. I want to prevent users from entering any characters except digits from 0-9. I managed to achieve this successfully with a solution that is resistant to copy-paste: C ...

Display the div according to the $index selected from the AngularJS list

Below is the structure of my HTML code: <div class="col-md-4"> <ul class="list-group text-left"> <a href="#" class="list-group-item" ng-click="showData($index)" ng-repeat="field in Data"> {{ field.name }}</a> ...

The ngModel feature is not functioning properly when trying to update in tag inputs

I am having trouble with two-way data binding using ngModel in tag-inputs. Can someone please assist me? Here is the link to my code on StackBlitz ...

Is it possible to utilize mathematical operators such as multiplication, division, addition, subtraction, and exponentiation to transform a non-zero numerical value into

I am currently working with Oracle Siebel software which supports JavaScript expressions using only specific operators such as multiply, divide, subtract, add, and XOR (*, /, -, +, ^). Unfortunately, other operators like ! or ? : are not available for use. ...

Mixing Jest and Cypress in a TypeScript environment can lead to Assertion and JestMatchers issues

When utilizing [email protected] alongside Jest, we are encountering TypeScript errors related to Assertion and JestMatchers. What is the reason for these TypeScript errors when using Jest and [email protected] in the same project? ...

What is the best way to send a JavaScript array to a Perl script using AJAX?

Is it possible to convert a JavaScript array passed via AJAX into a Perl array? Accessing in Perl: @searchType = $cgi->param('searchType'); print @searchType[0]; Result: employee,admin,users,accounts It appears that the first value in the ...

Can I send both a list of files and an entire JSON object in a FormData object to an ASP.NET CORE MVC Controller?

I'm looking for a way to send a formdata object to an MVC controller that includes both a JSON object with nested objects and a list of files. I've attempted to stringify the object into a JSON object, but the controller is unable to read the pro ...

Duplicate entries being saved in the database due to Ajax calls

I am currently utilizing Fullcalendar jQuery with PHP for managing events. I am making an AJAX call to add events, and while it works fine for the initial event entry after a page refresh, it starts creating duplicate events for subsequent entries. I am un ...

PHP code cannot be executed due to a problem with Angular routing

I stumbled upon this previous discussion during my search for assistance with a particular problem, but unfortunately there were no responses that could provide a solution. The issue I am facing involves submitting a form and expecting to receive a php va ...

What are the steps to run and test the renovate bot on your local machine

Before setting up renovate to work with my Azure pipeline, I wanted to test it locally using npx renovate to ensure everything is working as expected and that my config file is properly configured. I ran npx renovate --platform local command. My project i ...

Adjusting the contenteditable feature to place the caret on a specific child node

I am experiencing some challenges when attempting to position the cursor after an <i> tag within a contenteditable element. Currently, this is what I have: <p contenteditable="true"><i>H</i><i>e</i><i>l</i> ...