Using Long Polling with Angular 4

I am looking for a way to monitor the progress of a certain task using API calls.

To achieve this, I have developed a service that executes these API calls every 1.5 seconds

Main Component

private getProgress() {
        this.progressService.getExportProgress(this.type, this.details.RequestID);
    }

Services.ts

public getExportProgress(type: string, requestId: string) {
    Observable.interval(1500)
        .switchMap(() => this.http.get(this.apiEndpoint + "Definition/" + type + "/Progress/" + requestId))
        .map((data) => data.json().Data)
        .subscribe(
        (data) => {
            if (!data.InProgress)
                // Stop further API calls here
        },
        error => this.handleError(error));
}

Although the API call is functioning properly, it continues even after the progress is complete (if (!data.InProgress). I need help in figuring out how to unsubscribe from the observable when this condition is met.

Any suggestions on how I can implement an unsubscribe feature based on if (!data.InProgress)?

Appreciate any guidance

Answer №1

One possible solution is to utilize the takeWhile operator.

For more information, refer to the official documentation: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-takeWhile

The main functionality of this operator is to emit values from the source Observable only when they satisfy a certain condition specified by the predicate function. It then completes as soon as one value does not meet this condition anymore.

Here's a basic example scenario showcasing how it can be used:

Rx.Observable
  .interval(100)
  .takeWhile(x => x < 10)
  .subscribe(x => { console.log(x); });

Below is an example implementation using your code:

public getExportProgress(type: string, requestId: string) {
    Observable.interval(1500)
        .switchMap(() => this.http.get(this.apiEndpoint + "Definition/" + type + "/Progress/" + requestId))
        .map((data) => data.json().Data)
        .takeWhile((data) => data.InProgress)
        .subscribe(
        (data) => {
            ...
        },
        error => this.handleError(error));
}

Answer №2

I found a solution by storing the service call in a variable and unsubscribing from it when finished.

Below is the updated code snippet:

public getExportProgress(type: string, requestId: string): any {
    let progress = Observable.interval(1500)
        .switchMap(() => this.http.get(this.apiEndpoint + "Definition/" + type + "/Progress/" + requestId))
        .map((data) => data.json().Data)
        .subscribe(
        (data) => {              
            if (!data.InProgress) {
                this.toastyCommunicationService.addSuccesResponseToast("done");
                progress.unsubscribe();
            }            
        },
        error => this.handleError(error));
}

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

Updating non-data properties dynamically in a custom AG Grid cell renderer

In my grid setup, I have implemented an editor button in a column for each row and a new item creator button outside the grid. One of the requirements is that all buttons should be disabled when either the create or edit button is clicked. To achieve thi ...

Is it possible to navigate to a different section of a webpage while also jumping to a specific id within that section seamlessly?

I'm trying to create a navbar link that will take me directly to a specific section of a page, but I'm having trouble getting it to work. Here's what I've tried: <a href="home#id" class="nav-link text on-hover"></a> Where ...

Error: Platform core encountered a StaticInjectorError[t]: It is not possible to assign a value to the property '_injector', as it is undefined

This source code includes a rest API call and global variable reference. I have only utilized bootstrap CSS and omitted saving jQuery because bootstrap.js is not being used. After performing the (ng build -prod) command, I receive production build files ...

Can you explain how to utilize the 'npm' command and its functions?

Understanding npm: As I delve into various projects, they often direct me to utilize npm commands like this one: npm install -g node-windows I decided to explore npm by reading some blog posts and installing Node.js. However, upon attempting to run the a ...

Isolating a service from a component based on conditions in Angular 5

Within my root module, I have a service that is shared among all components. One of these components is named ComponentX module providers: [ BiesbroeckHttpService ], component constructor(private biesbroeckHttpService: BiesbroeckHttpService){} Som ...

is there a way to modify the background color of a div element by comparing values in javascript?

Is there a way to dynamically update the background color of a div element within a table based on values stored in a json array from a database? ...

Obtain the last used row in column A of an Excel sheet using Javascript Excel API by mimicking the VBA function `Range("A104857

Currently in the process of converting a few VBA macros to Office Script and stumbled upon an interesting trick: lastRow_in_t = Worksheets("in_t").Range("A1048576").End(xlUp).Row How would one begin translating this line of code into Typescript/Office Scr ...

What is the capability of dynamically generating an index in Typescript?

Can you explain why the Typescript compiler successfully compiles this code snippet? type O = { name: string city: string } function returnString(s: string) { return s } let o1: O = { name: "Marc", city: "Paris", [returnString("random")]: ...

Using an external variable within an internal function in TypeScript

I am facing a situation where I have a variable outside of a function that needs to be updated, but I am unable to access it using "this" as it is not reachable at that point in the code. export class GamesDetailPage { details : any = {}; type : St ...

How is babel-loader / tsc compiler able to distinguish between importing a package for its types only and for its functionalities?

Currently, I am integrating Typescript into my project. During this process, I made an interesting discovery. In the App.tsx file below, you will notice that I needed to use import firebase from "firebase/app" in order to access the firebase.ap ...

How can I dynamically replace a specific element inside a .map() function with a custom component when the state updates, without replacing all elements at once?

I'm currently developing a task management application and I need to enhance the user experience by implementing a feature that allows users to update specific tasks. When a user clicks on the update button for a particular task, it should replace tha ...

When incorporating a JS React component in TypeScript, an error may occur stating that the JSX element type 'MyComponent' is not a valid constructor function for JSX elements

Currently, I am dealing with a JavaScript legacy project that utilizes the React framework. Within this project, there are React components defined which I wish to reuse in a completely different TypeScript React project. The JavaScript React component is ...

What is the process for integrating Angular files into an Express server?

I am trying to figure out how to host Angular files on my Express server. My friend created some web pages using Angular and I have an Express server set up. I have tried searching for a solution online but have not been successful. I have looked at some p ...

Incorrect typings being output by rxjs map

combineLatest([of(1), of('test')]).pipe( map(([myNumber, myString]) => { return [myNumber, myString]; }), map(([myNewNumber, myNewString]) => { const test = myNewString.length; }) ); Property 'length' does not ...

What is the Angular lifecycle event that occurs after all child components have been initialized?

Seeking help with implementing a concept for the following scenario: I have a parent search component containing several child components for displaying facets and search results. I want to automatically trigger a search once the application has finished ...

I am encountering a problem with my component as the Angular Directive is missing

Recently, I incorporated a customized directive into my Angular app to allow file uploads via drag and drop. However, I encountered an issue where the command line kept throwing an error stating that my function does not exist within my component. Propert ...

Is there a way to prevent QtLinguist from opening every time Visual Studio tries to display a TypeScript file?

Ever since I installed Qt tools for Visual Studio, my Ctrl+click on a class name triggers Qt Linguist: https://i.stack.imgur.com/USAH1.png This hinders me from checking type definitions, even though Visual Studio has already parsed them. The type informa ...

Exclude a select few rows in MatSort, rather than excluding entire columns

When the user clicks on the Date column for sorting, it is required to exclude empty rows from the sorting. Empty rows are present due to the application of ngIf on those particular rows. The requirement states that rows with empty column values should eit ...

Limiting the height of a grid item in MaterialUI to be no taller than another grid item

How can I create a grid with 4 items where the fourth item is taller than the others, determining the overall height of the grid? Is it possible to limit the height of the fourth item (h4) to match the height of the first item (h1) so that h4 = Grid height ...

Search timeout restriction

I have a function that makes a request to the server to retrieve data. Here is the code for it: export default class StatusChecker { constructor() { if (gon.search && gon.search.searched) { this.final_load(); } else { this.make_req ...