Stop/Restart Requests When User Is Inactive using Angular, RxJS, and Page Visibility API
Tags: angular, rxjs, api, javascript
Published: 2022-10-06 13:35:32

It’s common for websites or apps to request fresh data on a set interval. What if the user isn’t looking at your website or app anymore? What if they minimized the browser or switched to a different tab or app? Let’s learn how to stop and restart network requests using the Page Visibility API!

## Setup

We want to create a service that will be responsible for getting a random quote from the [Quotable API](https://github.com/lukePeavey/quotable). We need to import some things we’ll use within the service. Let’s get those set up now.

```javascript
import { HttpClient } from '@angular/common/http';
 
import { BehaviorSubject, fromEvent, Observable, Subject, timer } from 'rxjs';
import { map, repeatWhen, switchMap, takeUntil, tap } from 'rxjs/operators';
```

Let’s define an interface for what the Quote will look like.

```javascript
interface Quote {
  _id: string;
  authorSlug: string;
  content: string;
  dateAdded: string;
  dateModified: string;
  length: number;
  tags: string[];
}
```

Let’s set up the variables we’ll be using as well.

```javascript
private readonly _restartTimer = new Subject<void>();
private readonly _stopTimer = new Subject<void>();
 
private readonly _randomQuote = new BehaviorSubject<Quote | null>(null);
 
readonly randomQuote$ = this._randomQuote.asObservable();
```

To display the actual quote, we can use the [async pipe](https://angular.io/api/common/AsyncPipe) to subscribe to the observable we created called **randomQuote$**.

```javascript
<blockquote *ngIf="randomQuote$ | async as randomQuote">
  {{ randomQuote.content }}
</blockquote>
```

## Get Random Quote

We want to use the [HttpClient](https://angular.io/api/common/http/HttpClient) to make HTTP requests to the Quotable API. Within the service’s constructor, pass in the following:

```javascript
constructor(private http: HttpClient) {}
```

Now let’s create a function called **getRandomQuote**. It will make a GET request to the Quotable API and return a random quote. The returned quote will be passed to the randomQuote BehaviorSubject.

```javascript
private getRandomQuote(): Observable<Quote> {
  return this.http.get<Quote>('https://api.quotable.io/random').pipe(
    tap(quote => this._randomQuote.next(quote))
  );
}
```

## Get Random Quote Every Minute

Now that we can get a random quote, let’s try getting one every minute! We’ll need the RxJS [timer](https://rxjs.dev/api/index/function/timer) function to run every minute and the RxJS [switchMap](https://rxjs.dev/api/operators/switchMap) operator to switch to the observable that gets the random quote after a minute has passed.

Create a function called **createTimer**. It will create the timer and get a random quote every minute. The time is in milliseconds so 60,000 milliseconds equals 1 minute.

```javascript
private createTimer(): void {
  timer(0, 60000).pipe(
    switchMap(() => this.getRandomQuote())
  ).subscribe();
}
```

## Stop/Restart Timer

We need a way to stop and restart the timer. Let’s create two functions for that called **restartTimer** and **stopTimer**. Both will call next on their respective Subjects to trigger the action.

```javascript
private restartTimer(): void {
  this._restartTimer.next();
}
 
private stopTimer(): void {
  this._stopTimer.next();
}
```

Now let’s update our createTimer function and add in a couple more operators. The [takeUntil](https://rxjs.dev/api/operators/takeUntil) operator will listen for the stopTimer Subject to trigger. If it is triggered, it will stop the timer. The [repeatWhen](https://rxjs.dev/api/operators/repeatWhen) operator will listen for the restartTimer Subject to trigger. If it is triggered, it will restart the timer.

```javascript
private createTimer(): void {
  timer(0, 60000).pipe(
    takeUntil(this._stopTimer),
    repeatWhen(() => this._restartTimer),
    switchMap(() => this.getRandomQuote())
  ).subscribe();
}
```

## Page Visibility API

We’re getting a random quote every minute, but what if the user isn’t looking at our website or app anymore? What if they minimized the browser or switched to a different tab or app? Let’s stop getting a random quote every minute until the user comes back.

There is a helpful event called [visibilitychange](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilitychange_event) that we can listen for. It provides a [visibilityState](https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState) property that will tell you whether the page content is **visible** or **hidden** to the user.

Create a function called **onVisibilityChange** that will listen for the visibilitychange event. If the visibility state is visible, we can restart the timer. If not, stop the timer.

```javascript
private onVisibilityChange(): void {
  fromEvent(document, 'visibilitychange').pipe(
    tap((event: Event) => {
      const state = (event.target as Document).visibilityState;
 
     if (state === 'visible') {
        this.restartTimer();
      } else {
        this.stopTimer();
      }
    })
  ).subscribe();
}
```

All that’s left to do is call the **createTimer** and **onVisibilityChange** functions in the constructor.

```javascript
constructor(private http: HttpClient) {
  this.createTimer();
  this.onVisibilityChange();
}
```

Congrats on saving server resources when the user isn’t actively using your website or app!

---
**Visit our website at [https://nightwolf.dev](https://nightwolf.dev) and follow us on [Twitter](https://twitter.com/nightwolfdev)!**