04th June 2024

Effective Server Polling using RxJS Observables in Angular

Server-Polling-VS-Online-img

Server polling is a technique where a client application periodically fetches data from a server to keep its UI up to date with real-time or frequently changing information. It's a common approach for scenarios like:

  • Tracking long-running background processes
  • Displaying live chat updates
  • Monitoring server logs or sensor data

Leveraging RxJS for Robust Polling

Angular heavily utilizes RxJS, a powerful library for reactive programming. RxJS provides Observables, which are streams of data that emit values over time, and operators, which manipulate these streams. We'll employ RxJS operators to create a robust polling mechanism.

In this guide, we'll explore how to implement server polling using RxJS in an Angular project.

Prerequisites
  • Node.js and npm: Ensure you have Node.js and npm installed.
  • Angular CLI: Install the Angular CLI globally using npm. You can do this by running.
                                
                                    
    npm install -g @angular/cli
  
                                
                            
Versions Used

Here are the versions of the tools and libraries used in this guide:

  • Node.js: v18.16.0
  • npm: v9.5.1
  • Angular CLI: v16.1.2
  • Angular: v16.1.2
  • RxJS: v7.8.1

Step-by-Step Guide to Implementing Server Polling in RxJS

Now, let's proceed with the detailed guide.

Step 1: Setting Up the Project

First, we need to set up a new Angular project. Follow these steps:

  • Create a New Angular Project: Open your terminal and run the following commands to create a new Angular project and navigate into the project directory:
                                
                                    
    ng new rxjs-server-polling
    cd rxjs-server-polling
  
                                
                            

Angular comes with RxJS by default, so no additional installation is needed.

Step 2: Setting Up a Development Backend Server

We'll set up a simple Node.js server that generates dynamic data.

  • Create the Server: In your project root directory, create a new directory named server:
                                
                                    
    mkdir server
    cd server
  
                                
                            
  • Initialize a Node.js Project: Run the following command to initialize a new Node.js project:
                                
                                    
    npm init -y
  
                                
                            
  • Install Express and CORS: Install Express, a fast, unopinionated, minimalist web framework for Node.js, and CORS middleware to handle Cross-Origin Resource Sharing:
                                
                                    
    npm install express cors
  
                                
                            
  • Create the Server Script Create a new file named server.js in the server directory and add the following code:
                                
                                    
    const express = require('express');
    const cors = require('cors');
    const app = express();
    const port = 3000;
    
    // Enable CORS
    app.use(cors());
    
    // Generate dynamic data
    function getRandomData() {
      return {
        value: Math.floor(Math.random() * 100),
        timestamp: new Date().toISOString()
      };
    }
    
    app.get('/data', (req, res) => {
      res.json(getRandomData());
    });
    
    app.listen(port, () => {
      console.log('Server is running on http://localhost:port');
    });
  
                                
                            
Explanation:
  • CORS: We use the cors middleware to enable CORS.
  • getRandomData: This function generates a random data object with a value between 0 and 100 and a timestamp.
  • GET /data: This route responds with the dynamic data generated by getRandomData.
  • Server Setup: We set up the server to listen on port 3000.
  • Run the Server Start the server by running the following command in the server directory:
                                
                                    
    node server.js
  
                                
                            

You should see the message "Server is running on http://localhost:3000" in your terminal.

Step 3: Creating a Polling Service

The polling logic will reside in a dedicated service. This service will handle the periodic HTTP requests to the server.

  • Generate the Service: Run the following command to generate a new service named polling:
                                
                                    
    ng generate service polling
  
                                
                            
  • Implement the Polling Logic Open polling.service.ts and add the following code:
                                
                                    
    import { Injectable } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    import { Observable, timer } from 'rxjs';
    import { switchMap } from 'rxjs/operators';
    
    @Injectable({
      providedIn: 'root'
    })
    export class PollingService {
      private pollingInterval = 5000; // 5 seconds
      private apiUrl = 'http://localhost:3000/data'; // Backend server URL
    
      constructor(private http: HttpClient) { }
    
      getPollingData(): Observable<any> {
        return timer(0, this.pollingInterval).pipe(
          switchMap(() => this.http.get(this.apiUrl))
        );
      }
    }
  
                                
                            
Explanation:
  • Imports: We import necessary modules from Angular and RxJS. HttpClient is used to make HTTP requests, Observable and timer are from RxJS, and switchMap is an RxJS operator.
  • @Injectable: This decorator marks the class as a service that can be injected into other components or services.
  • PollingService: This is our service class.
  • pollingInterval: This variable defines how often (in milliseconds) we want to poll the server (5 seconds in this case).
  • apiUrl: This variable holds the URL of our backend server.
  • constructor: The constructor injects the HttpClient.
  • getPollingData: This method returns an Observable that emits data from the server at regular intervals.
  • timer(0, this.pollingInterval): This creates an Observable that starts emitting immediately (0 delay) and then every 5 seconds.
  • switchMap: This operator maps each emitted value from the timer to a new Observable (an HTTP GET request in this case), ensuring that only the latest request is active.

Step 4: Creating a Component to Use the Service

Next, we need a component that will use the polling service to fetch and display data.

  • Generate the Component: Run the following command to generate a new component named polling-demo:
                                
                                    
    ng generate component polling-demo
  
                                
                            
  • Update the Component Logic: Open polling-demo.component.ts and add the following code:
                                
                                    
    import { Component, OnInit } from '@angular/core';
    import { PollingService } from '../polling.service';
    
    @Component({
      selector: 'app-polling-demo',
      templateUrl: './polling-demo.component.html',
      styleUrls: ['./polling-demo.component.css']
    })
    export class PollingDemoComponent implements OnInit {
      data: any;
    
      constructor(private pollingService: PollingService) { }
    
      ngOnInit(): void {
        this.pollingService.getPollingData()
          .subscribe(response => this.data = response);
      }
    }

                                
                            
Explanation:
  • Imports: We import necessary modules from Angular and the PollingService we created earlier.
  • @Component: This decorator defines metadata for the component, such as the selector, template URL, and styles.
  • PollingDemoComponent: This is our component class.
  • data: This property will hold the data fetched from the server.
  • constructor: The constructor injects the PollingService.
  • ngOnInit: This lifecycle hook is called once the component is initialized. We use it to subscribe to the polling service and update the data property with the server response.
Update the Component Template

Open polling-demo.component.html and add the following code to display the fetched data:

                                
                                    
  <div *ngIf="data">
  <pre>{{ data | json }}</pre>
  </div>

                                
                            
Explanation:
  • *ngIf: This structural directive conditionally includes the div element in the DOM if data is not null or undefined.
  • "
    "data"
    :"
    This displays the data object in a formatted JSON string within a pre tag, which preserves whitespace and formatting.

Step 5: Adding HTTP Client Module

Ensure the HttpClientModule is imported in your app.module.ts so that HTTP services can be used.

1. Update app.module.ts

Open app.module.ts and add the following imports and declarations:

                                
                                    
  import { BrowserModule } from '@angular/platform-browser';
  import { NgModule } from '@angular/core';
  import { HttpClientModule } from '@angular/common/http';
  
  import { AppComponent } from './app.component';
  import { PollingDemoComponent } from './polling-demo/polling-demo.component';
  
  @NgModule({
    declarations: [
      AppComponent,
      PollingDemoComponent
    ],
    imports: [
      BrowserModule,
      HttpClientModule
    ],
    providers: [],
    bootstrap: [AppComponent]
  })
  export class AppModule { }

                                
                            
Explanation:
  • Imports: We import BrowserModule and HttpClientModule.
  • declarations: We declare the AppComponent and PollingDemoComponent.
  • imports: We import BrowserModule and HttpClientModule to the @NgModule.
  • bootstrap: We bootstrap the AppComponent.

Step 6: Running the Application

Finally, let's run the Angular application to see the server polling in action.

Run the Application

Open your terminal in the project root directory and run the following command:

                                
                                    
  ng serve

                                
                            
Open the Application

Navigate to http://localhost:4200 in your web browser. You should see the data being fetched from the server and displayed at regular intervals (every 5 seconds).

Understanding the Code

  • PollingService: This service is the core of our polling mechanism. It uses the timer function from RxJS to create an Observable that emits values at the specified interval (every 5 seconds). The switchMap operator maps each emitted value from the timer to a new Observable (an HTTP GET request in this case), ensuring only the latest request is considered.
  • PollingDemoComponent: This component subscribes to the polling service to receive the data and updates its local data property with the server response, which is displayed in the template.

Conclusion

Server polling is a powerful technique for keeping your application updated with the latest data. By leveraging RxJS, you can implement efficient and straightforward polling mechanisms. This guide walked you through setting up a basic Angular application that polls a server for data at regular intervals, including setting up a backend server to generate dynamic data.

Feel free to experiment with different intervals and endpoints to see how the polling behaves in different scenarios. Happy coding!

Let's develop your ideas into reality