1

I need run a function if neither the mouse has moved, nor the keyboard has been touched for 1mn.

I tried the code below but doesn't seem to work. How can I fix it? Thank you for your help.

mouseEvent$ = fromEvent(document, 'mouseMove');
keyPress$ = fromEvent(document, 'keyup');

merge(
    this.mouseEvent$.pipe(startWith(null)).pipe(switchMap(() => timer(10000, 1000))),
    this.keyPress$.pipe(startWith(null)).pipe(switchMap(() => timer(10000, 1000))),
).subscribe(() => console.log("----));
user1445685
  • 793
  • 1
  • 11
  • 25

2 Answers2

2

Here's my take on this:

 const mouseMove$ = fromEvent<MouseEvent>(document, 'mousemove');
 const keyPress$ = fromEvent<KeyboardEvent>(document, 'keyup');
 const mergeBothEvents = merge(keyPress$, mouseMove$);
 const interval$ = timer(60000);
 
 mergeBothEvents
     .pipe(
       startWith('initial'),
       switchMap(() => {
         return interval$;
       })
     )
     .subscribe(() => {
       console.log('60 seconds past');
       console.log('Perform function here');
     });

A bit of inside into what's happening in the code.

fromEvent<MouseEvent> used to capture the mouse movements.

fromEvent<KeyboardEvent> used to capture the keyboard key up click event.

merge(keyPress$, mouse$) is used to merge both the observables so that they can run in parallel.

timer(60000) is used to check the time of a minute before running the required function.

In mergeBothEvents we have used to more operators startWith() and switchMap

startWith() is used for the edge-case in which if the user doesn't do anything(mouse or keyboard) when he enters the page the mergeBothEvents event won't be emitted. Thanks @MrkSef to for pointing that out.

Finally switchMap is used to cancel the previous subscription of the event when the user moves the mouse or presses the keyboard so the timer restarts from 0th second.

HassanMoin
  • 2,024
  • 1
  • 6
  • 16
  • This will only start the timer once `mergeBothEvents` emits. Once it emits, it will only start the next timer on the next emission. – Mrk Sef Feb 09 '22 at 19:00
  • @MrkSef, for learning purposes any update to this method that will ensure it works properly? or is it a lost cause? :D – HassanMoin Feb 09 '22 at 20:40
  • @MrkSef, so this fails for the edge case that if the user doesn't move the mouse or press any key then `mergeBothEvents` won't emit, and hence the timer won't start, correct? Adding the `startWith('Initial')` fixes this edge case ? – HassanMoin Feb 09 '22 at 22:01
  • This solution seems to work for my case. Thank you very much! – user1445685 Feb 09 '22 at 22:43
0

The first thing to notice is that you typed mouseMove incorrectly.

Here's how I might do this:

merge(
  fromEvent(document, 'mousemove'),
  fromEvent(document, 'keyup')
).pipe(
  share(),
  startWith(null),
  debounceTime(60000),
  take(1),
  retry()
).subscribe(_ => console.log("1 Minute without input"));
Mrk Sef
  • 7,557
  • 1
  • 9
  • 21
  • can you please explain what is the use of share() and retry() in this solution? – Aakash Goplani Feb 09 '22 at 19:37
  • Hi. Thank you for your answer. But it seems like with your solution, when the timeout occurs, you have to move the mouse or press a key to get the listener restart again – user1445685 Feb 09 '22 at 22:21