2

In my angular apps, I want to show a text/modal that have a cancel and reload button, when the server responds slowly.

If the user click cancel, current http request will be cancelled. If the user click reload, current http request will be retried. If the text/modal already shown and the HTTP request already respond/completed, then the text/modal should disappear.

I have an idea using HTTP interceptor, RxJS, and global service, but implementing it is not that easy.

Is there anyone who have an idea, how to do this the right way?

EDIT: Oh and I want to make it a generic module so every http request can be cancellable or reloadable. So every page could have this functionality

flemadap
  • 639
  • 8
  • 18
  • can you create a stackblitz on what you have tried till now? – Siddharth Pal Dec 11 '19 at 08:53
  • I am sorry, no. Still trying some idea. What I do currently is using a service which have onCancel and onReload observables. And from Interceptor try to subscribe from those observables. I need others' opinion though – flemadap Dec 11 '19 at 08:57

4 Answers4

0

Suppose your request will take 20 sec to complete response then you able to cancel that within 20 sec

By Simply UnSubscription That request

import { Component, OnInit, OnDestroy } from '@angular/core';
    import { Subscription } from 'rxjs/Rx';

    export class Component implements OnInit, OnDestroy {
        private subscription: Subscription;
        ngOnInit() {
            this.subscription = this.route.params.subscribe();
        }
        ngOnDestroy() {
            this.subscription.unsubscribe();
        }



     cancel() {
            this.subscription.unsubscribe();
        }

    retry() {
            this.subscription.subscribe();
        }



    }

html You can a popup when or any place which button when you make any http request so able to cancel it

     <div> {{ subscription | async }}</div>
.
.
.Enter your other logic
.


    <button (click)=="cancel()" > Cancel Request</button>
    <button (click)=="retry()" > Cancel retry</button>
harkesh kumar
  • 833
  • 2
  • 13
  • 35
0

You need to use reportProgress of HttpRequest. There is an explanation how to do it here https://stackoverflow.com/a/47034525/9590251. But keep in mind that it will listen to every change detection, thus slowing down app performance a lot. It it recommended to use for a heavy requests (ie file uploading)

Timothy
  • 3,213
  • 2
  • 21
  • 34
0

Cancel/abort all pending HTTP requests with takeUntil

You can use takeUntil to stop an ongoing request, because a request from HttpClient returns an observable you can do it quite easy:

TS

userStop$: Subject<boolean> = new Subject<boolean>();

makeRequest() {
    this.userStop$.next(false);
    // Service Call
    this.apiService.makeRequest().pipe(
        takeUntil(this.userStop$)
    ).subscribe(...);
}

handleUserStop() {
    this.userStop$.next(true);
}

When you change the userStop$ to true with a button click for example it will stop. To retry you can simply recall the service method and set the userStop$ to false;

If you want to retry the request after it failed, you can use retry(x).

this.apiService.makeRequest().pipe(
    //retry 2 times on error
    retry(2)
).subscribe(...);

You can also checkout this: How to cancel/unsubscribe all pending HTTP requests angular 4+

For more information: https://www.learnrxjs.io/operators/filtering/takeuntil.html

Ling Vu
  • 4,740
  • 5
  • 24
  • 45
  • I already have a code similar to this. But is there any way, for each http request, to count the time it tooks for getting response, and then show the user the option to cancel or redo the request observable stream. – flemadap Dec 11 '19 at 10:22
  • Cancel a request will obviously finish the observable. For those you can use a `Subject` to constantly push new requests, but getting a `404` or a timeout will always finish the observable, because of a throwing error. You need to setup a fallback value in case of an error. – Ling Vu Dec 11 '19 at 10:34
  • Other than that your discription looks a bit unclear what you really want. Using takeUntil should achive what you want: The user can retry the request and cancel it. – Ling Vu Dec 11 '19 at 10:36
0
  1. Create a cancelable subscription

That one is easy. Create a property in the component like this:

dataSubscription: Subscription

and in the event handler where you fire the request, create it like this:

dataSubscription = someService.someRESTApiCalls.subscribe(....)

any time, you want to stop this, you can call

this.dataSubscription.unsubscribe()

I also recommend to utilize the ngOnDestroy hook, and unsubscribe from it if needed:

ngOnDestroy(){

   if(this.dataSubscription) this.dataSubscription.unsubscribe();
}

to cancel the call.

  1. Modals

For modals, I recommend the Angular Material Modal

  1. Logic

Create a class property in the component isResponseArrived: boolean or something. After the user initiates the request, in the event handler set it to false, and show whatever you want to shuw, with an ngIf="!isResponseArrived"˛ After the response arrived, modify the flags value to true in the subscription reponse handler (both with value, or on error).

+1: detect if the subscription is taking too long

Use the httpClient timeout (source):

this.httpClient.get(url, { headers: headers })
        .timeout(30000)
        .subscribe(
            (response) => {
                ...
            },
            error => {
                ...
            }
                ...
            );
ForestG
  • 17,538
  • 14
  • 52
  • 86
  • How to detect if the subscription taking longer than x seconds?? And after I know that the respond take a long time, I can cancel or reload it. – flemadap Dec 11 '19 at 09:12
  • Doesn't timeout automatically errored/completed the stream? Is there any way to not to complete the stream? Let the client still waiting for response but at the same time, user get the notification that the current http is taking a long time and could cancel or redo it. – flemadap Dec 11 '19 at 10:20