Replay subscription in Angular 2 using RxJS 5, triggering the schedule based on the previous result

Within my Angular 2 application written in typescript 2, a server query is made to retrieve a value that requires regular updates based on an expiration date provided by the server.

I am facing difficulties in creating an Observable stream that will automatically trigger a new call to the server once the current value has expired. The approach I have taken so far is not efficient at all:

price = 5; //initial known value
expires = ...;//initial known expiration

getData(){
    // server response contains {expires:number, price:number}
    this.http.get('...').map(res => res.json())
}

Observable.timer(expires-Date.now()) // when initial price expires
    .switchMap(()=>this.getData()) // fetch new price and expiration
    .subscribe( data =>
        {
            this.price = data.price;
            Observable.timer(data.expires-Date.now()) //redo when price expires
                .switchMap(()=>getData())
                .subscribe(...) //nested callbacks (endless blocks)
        }
    );

There must be a more efficient way to schedule subsequent calls after the initial query.

Answer №1

Execute the doObservableStuff function initially whenever necessary.

fetchData(){
    // The server responds with {expires:number, price:number}
    this.http.get('...').map(res => res.json())
    .subscribe( data =>
        {
            this.price = data.price;
            doObservableStuff(data.expires-Date.now())
        });
}

doObservableStuff(time){
    Observable.timer(time)
    .switchMap(() => this.fetchData())
}

Answer №2

To create a delay before starting the observable chain and continuously fetch fresh data, I implemented a strategy using switchMap() paired with timer() for timing and repeat() to ensure ongoing updates:

price = 0;    //initial price
_exp  = 0; //initial delay before fetching data

/** Observable will emit after the expiration delay */
wait() {return Observable.timer(this._exp*1000)}

stream$ = Observable.of(null)
    .switchMap(()=>this.wait()) // wait for the expiration delay                
    .switchMap(()=>this.getServerData()) // get fresh data
    .do(e=>{this._exp = e.expires}) //update expiration             
    .repeat() // repeat until the calling code unsubscribes

Upon subscription, the first price is retrieved immediately, followed by continuous retrievals at intervals determined by the expires value. This allows real-time updates to be reflected in the model:

ngOnInit(){
    this.stream$.subscribe( e=>this.price = e.price);
}

Check out the live demo

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

Tips for adjusting the maximum characters per line in tinyMCE 5.0.11

I have an angular 8 application that utilizes tinyMCE, and I am looking to limit the maximum number of characters per line in the textArea of tinyMCE. My search for a solution has been unsuccessful so far despite extensive googling efforts. (image link: [ ...

The Angular animation using :leave/:enter appears to only have an effect when the page is refreshed

I'm in the process of developing an Angular animation, but it seems like it's not working as expected at the moment. Here is my code snippet: trigger("fadeInOut", [ transition("* => *", [ query(":enter", [s ...

OnPush strategy and template updates: Propagating modifications to the parent component

I am currently facing an issue with a parent component that consists of two templates. The first template simply displays data-bound text, while the second template contains a child component responsible for updating the data model. Both the parent and chi ...

Implement feature to toggle function upon clicking radio buttons using bootstrap and angular 5

Currently, I am utilizing Angular 6 and Bootstrap 4. Within my project, there exists a Bootstrap button group: <div class="btn-group btn-group-toggle" data-toggle="buttons"> <label class="btn btn-secondary"> <input type="radio" ...

Implementing a dynamic star rating system in Angular

I am working with an array of ratings that looks like this: "rating": [ { "sno": 1, "question": 13, }, { "sno": 2, ...

What is the reason for importing this JS module in TypeScript with a "default" property?

This particular code snippet comes from a specialized i18n module, situated within ./esm/locale/en.js: import cardinal from '../rules/rule5'; import ordinal from '../rules/rule42'; var pluralRule = { ordinal: ordinal, cardinal: card ...

Getting a public state variable value from a Solidity smart contract using TypeScript: The ultimate guide

Is there a way to save the value of the public state variable highestBid in Solidity using JavaScript? I'm currently getting an undefined result and need help with this. TS: async getHighestBid() { this.smartAuction.setProvider(this.provid ...

Attempting to locate an element within the DOM using TypeScript

I am completely new to TypeScript. I have been attempting to locate an element using a selector, but no matter what I tried, the findElement() method always returns undefined. Can someone please point out where my mistake might be? Any assistance would b ...

Visibility of an Angular 2 directive

It's frustrating that I can't change the visibility of a reusable directive in Angular2. 1) Let's say I have a login page. I want to control the visibility of my navbar based on whether I am on the login page or logged in. It should be hid ...

Enhancing Angular 5 with CustomEvent Polyfill for JavaScript

After implementing the code snippet in main.ts file, I encountered an issue with CustomEvent not being added to the window object correctly. Strangely, when I manually add CustomEvent using the JavaScript console, it works fine. This problem arises specifi ...

Leverage elements from nearby npm repository when building an Angular 2 application

After developing a generic chart component using d3 and Angular 2, I decided to share it by publishing it in a local npm repository. This way, anyone can easily incorporate the chart component into their Angular project by simply running the npm install my ...

What is the best way to restrict a React input field to have values within the minimum and maximum limits set by its

As a newcomer to React, I am working on restricting my input to values between -10 and 10. Currently, the input is set up to accept any value, and I am utilizing hooks like useState and useEffect to dynamically change and set the input value. My goal is ...

Can one invoke ConfirmationService from a different Service?

How can I declare an application-wide PrimeNG dialog and display it by calling ConfirmationService.confirm() from another service? Below is the HTML code in app.component.html: <p-confirmDialog [key]="mainDialog" class="styleDialog" ...

Necessary Typescript class property when executing code

Is there a way to determine if a class property is required in Typescript at runtime? export class A { public readonly ab?: number; public readonly ac?: number; public readonly ad: number; public readonly ae: number; } Can emitDecoratorMetadata o ...

The compatibility issues between Angular 5 and materialize-css (v 1.0.0) are causing obstacles in functionality

I attempted to implement the solution found on this post: Unfortunately, the solution didn't work as expected. I am working with Angular and Typescript in my project. Here is a snippet of my Typescript class: import { Component, OnInit, AfterVi ...

Sharing data between two components in an Angular2-Meteor application

I am currently working with angular2-meteor. When attempting to transfer a value between two components (updating the value in the first component triggers an event in the second component where the new value is used), I have two methods available: The ...

Expanding ngFor in Angular 2

Is it possible to pass two arguments with ngFor? Here is an example that I would like to achieve: <mat-card *ngFor="let room of arr; let floor of floorArr"> <mat-card-content> <h3>Room Number: {{room}}</h3> <p>Floor ...

What are the steps to set up ChartJS on a personal computer?

Currently, I am working on creating charts with ChartJS using the CDN version. However, I would like to have it installed directly on my website. After downloading ChartJS v4.1.1, I realized that it only contains typescript files. Since I cannot use TS fil ...

What is the most effective way to loop and render elements within JSX?

Trying to achieve this functionality: import React from 'react'; export default class HelloWorld extends React.Component { public render(): JSX.Element { let elements = {"0": "aaaaa"}; return ( ...

Is there a way to test a function call within ngOnChanges using Angular Jasmine?

In my Angular app, I have a child component that invokes a function in the ngOnChanges lifecycle hook. export class GameComponent implements OnInit, OnChanges { ngOnChanges(changes: SimpleChanges) { this.generateRandomIcon(); } generateRan ...