Angular 5, rxjs- wait for observable to finish only if it is in a middle of a run before running another process

danda

I have a timer in my main component of 3 seconds. inside the timer I perform http call-

    constructor(){
          this.timer = timer(3000, 3000);
          this.timerObservable = this.timer.subscribe(x => {
              this.http.get(URL).subscribe(()=>{
              //DO SOMETHING
              });
          });

     }

In another component I have a button that suppose to perform a different http call, pressing on the button invoke the sumbit function-

        submit(){
            this.http.get("/sumbitForm").subscribe(()=> {
              //DO SOMETHING
             })
         }

When a user clicks on the button, if the timer is in process (the http inside of it was called and not resolved yet) I want to wait before I perform the http call on the button until it resolved, but if the timer is not in process (the time from the previous call did not passed yet) I want to execute it immediately.

I think that forkJoin and concat is not relevant here (this is a timer and not a 'regular' subscription that I want to wait to its execution either way) and I could not find a pretty way to do it, any idea?

fridoo

You need to share some information between your two components, i.e. when the polling request is in progress and when it isn't. You should use a Service for this. It's also always good practice to move your http request logic to a Service instead of using the HttpClient directly in the component. This allows you to do your general error handling in one place. Let's call this Service ApiService.

ApiService

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject, interval } from 'rxjs';
import { switchMap, tap } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class ApiService {
  // Use a BehaviorSubject to notify listeners about ongoing polling requests.
  // A BahaviorSubject always has a current value that late subscribers will 
  // receive immediately upon subscribing
  private pollRequestInProgress = new BehaviorSubject<boolean>(false);
  // Share this BehaviorSubject as an Observable
  public pollRequestInProgress$ = pollRequestInProgress.asObservable();

  constructor(private http: HttpClient)

  doPoll(url: string): Observable<any> {
    return interval(3000).pipe( // interval(3000) is equivalent to timer(3000, 3000)
      tap(_ => pollRequestInProgress.next(true)), // notify that a poll request is about to happen
      switchMap(_ => this.http.get(url)), // do your poll request
      tap(_ => pollRequestInProgress.next(false)) // notify that your poll request ended
    );
  }
}

MainComponent

This is the Component where you want to start your polling from.

private destroy$: Subject<void> = new Subject<void>();

constructor(private apiService: ApiService) {}

// move logic to ngOnInit instead of constructor
ngOnInit() {
  // subscribe and thereby start the polling
  this.apiService.doPoll(URL).pipe(takeUntil(this.destroy$))
    .subscribe(pollResponse => {
      //DO SOMETHING
    });
}

ngOnDestroy() {
  // unsubscribe when the Component gets destroyed.
  this.destroy$.next();
  this.destroy$.complete();
}

FeatureComponent

This is the Component where you want to perform a http request when you click a button.

constructor(private http: HttpClient, private apiService: apiService) {}

submit() {
  // Listen to whether a polling request is currently in progress.
  // We will immediately receive a value upon subscribing here, because we used 
  // a BehaviorSubject as the underlying source.
  this.apiService.pollRequestInProgress$.pipe(
    // Emit the first item that tells you that no polling request is in progress.
    // i.e. let the first 'requestInProgress === false' through but not any 
    // other items before or after.
    first(requestInProgress => !requestInProgress),
    // If no polling request is in progress, switch to the http request you want 
    // to perform
    switchMap(this.http.get("/sumbitForm")) // <-- consider moving this http.get to your ApiService aswell
  ).subscribe(httpResponse => {
    // you've got your http response here
  });
  // you don't have to unsubscribe here as first and http.get both complete 
  // and thus unsubscribe automatically
}

Check out a simple example of the code logic above here: https://stackblitz.com/edit/rxjs-t4hjcr

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Wait for observable in for loop to finish before continuing loop in Angular 5

Angular Wait an Observable to finish before starting other Observable

How to wait until a asynchronous function finish running then only run continue another function in swift?

How to wait for a observable method to finish before proceeding in Angular 2

How to wait for a jQuery toggle to finish before running another function?

Wait for multiple http requests to finish before running a function in angular

RxJS - split Observable into two, wait for first to finish

How to wait for first Observable to finish before executing others in parallel using RxJS

Wait on RxJs.Subscriptions to finish before resuming

The gentleman, a RxJs timer which wait for process to finish executed before next interval

wait one process to finish and execute another process

wait for the process to finish to start another process

Wait for process to finish before proceeding in Java

Wait for async process to finish before redirect in koajs

RxJS wait for observable then create another observable, and so on

Wait for function to finish running before iterating

Angular rxjs: method does not wait for promise to finish

Using concatMap to run a Single before running another observable

Run methods in new process and wait for them to finish

Wait until function finish to run another function

RXJS Emit first result and then wait for another observable

Wait for a child process to finish before starting new child process

Angular/RxJS wait for HTTP response in inner Observable

How to Wait for windows process to finish before opening file in java

Node.JS: how to wait for a process to finish before continuing?

Jest: Wait for an async test to finish before running the next one

Wait for download method to finish before running next .then - node.js

Ionic 3 Wait for storage promise to completely finish before running function

How to wait for a loop to finish running before sending back a response in NodeJs?