Idle Detection

Idle detection is the process of monitoring user activity and determining when a user becomes inactive. This is particularly useful for applications that require users to remain logged in, as it allows the system to take appropriate action when a user stops interacting with the application, such as warning them of an impending timeout or automatically logging them out after a period of inactivity.

The Idle Detection Service provides configurable idle and timeout durations, automatic reset on user activity, event emission for idle and timeout phases, and reactive programming support through RxJS observables.

Examples

Example 1: Configure Idle Detection Globally

Configure idle and timeout durations globally using the configuration class:

export class IdleDetectionConfig {
  idleDurationInSeconds?: number;
  timeoutDurationInSeconds?: number;
}

Example 2: Module Configuration

Provide the configuration in your NgModule:

import { provideIdleDetectionConfig, IdleDetectionService } from 'ngx-lift';

@NgModule({
  providers: [
    // After 20 minutes of inactivity, a countdown starts with 300.
    provideIdleDetectionConfig({
      idleDurationInSeconds: 20 * 60, // 20 minutes for idle-detection phase
      timeoutDurationInSeconds: 5 * 60, // 5 minutes for timeout phase
    }),
  ],
})
export class AppModule {}

Example 3: Standalone App Configuration

Provide the configuration in a standalone application:

import { provideIdleDetectionConfig } from 'ngx-lift';

export const appConfig: ApplicationConfig = {
  providers: [
    provideIdleDetectionConfig({ idleDurationInSeconds: 20 * 60, timeoutDurationInSeconds: 5 * 60 }),
  ],
};

bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));

Example 4: Use IdleDetectionService in Component

Subscribe to the service's observables to react to idle events:

import {IdleDetectionService} from 'ngx-lift';
import {Component, inject, OnInit, OnDestroy} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';
import {DestroyRef} from '@angular/core';

@Component({})
export class AppComponent implements OnInit, OnDestroy {
  private idleDetectionService = inject(IdleDetectionService);
  private authService = inject(AuthService);
  private destroyRef = inject(DestroyRef);

  ngOnInit() {
    if (this.authService.isLoggedIn) {
      // setConfig is optional if you have idle configuration by provideIdleDetectionConfig
      // This will overwrite the config passed by provideIdleDetectionConfig
      this.idleDetectionService.setConfig({
        idleDurationInSeconds: 5 * 60,
        timeoutDurationInSeconds: 5 * 60,
      });

      // Most important, start to watch for user inactivity!
      this.idleDetectionService.startWatching();

      this.idleDetectionService
        .onIdleEnd()
        .pipe(takeUntilDestroyed(this.destroyRef))
        .subscribe(() => {
          // Handle idle end event, e.g., show a warning dialog
          console.log('idle detection phase ends, enter timeout phase');
        });

      this.idleDetectionService
        .onTimeoutEnd()
        .pipe(takeUntilDestroyed(this.destroyRef))
        .subscribe(() => {
          // Handle timeout end event, e.g., log out the user
          console.log('timeout phase ends, should logout user');
        });

      this.idleDetectionService
        .onCountDown()
        .pipe(takeUntilDestroyed(this.destroyRef))
        .subscribe((countdown) => {
          // Update the UI with the remaining time if needed
          console.log(countdown, 'display countdown in UI');
        });
    }
  }

  ngOnDestroy() {
    this.idleDetectionService.clearTimers();
  }
}

Example 5: Use IdleDetectionComponent

We provide a component in clr-lift that displays a Clarity modal dialog when the user is idle. The dialog will appear when the idle-detection phase concludes and start counting down. Once the countdown ends, you can hook into the timeout handler in your component to perform custom logic such as clearing the localStorage token and redirecting the user to the login page.

The parameters idleDurationInSeconds and timeoutDurationInSeconds are optional. When these parameters are passed, they will overwrite the configuration passed by provideIdleDetectionConfig.

import {IdleDetectionComponent} from 'clr-lift';
import {Component, inject} from '@angular/core';

@Component({
  imports: [IdleDetectionComponent],
  template: `
    @if (isLoggedIn) {
      <cll-idle-detection
        [idleDurationInSeconds]="15 * 60"
        [timeoutDurationInSeconds]="5 * 60"
        (timeout)="onTimeout()"
      />
    }
  `
})
export class AppComponent {
  isLoggedIn = inject(AuthService).isLoggedIn;

  onTimeout() {
    localStorage.removeItem('your-app-jwt');
    location.assign('/login');
  }
}

The dialog looks like below:

Idle Detection Dialog

API Reference

IdleDetectionService

Service for monitoring user activity and detecting idle periods.

Methods

  • setConfig(config: IdleDetectionConfig): void

    Sets the idle detection configuration. Overwrites the global configuration if provided.

  • startWatching(): void

    Starts monitoring user activity for idle detection.

  • clearTimers(): void

    Clears all timers and stops monitoring.

  • onIdleEnd(): Observable<void>

    Observable that emits when the idle-detection phase ends and the timeout phase begins.

  • onTimeoutEnd(): Observable<void>

    Observable that emits when the timeout phase ends.

  • onCountDown(): Observable<number>

    Observable that emits the countdown value during the timeout phase. Emits the remaining seconds.

IdleDetectionConfig Interface

  • idleDurationInSeconds?: number

    Duration in seconds for the idle-detection phase. After this period of inactivity, the timeout phase begins.

  • timeoutDurationInSeconds?: number

    Duration in seconds for the timeout phase. After this countdown, the timeout event is emitted.