"Implementing a retry feature for Angular http requests triggered by a button

Imagine having a situation where a component has a method that triggers an http request defined in a service. The observable is subscribed to within the component:

Component:

fetchData() {
    this.apiService.fetchDataFromServer().subscribe(
        response => console.log(response),
        error => console.error(error)
    );
}

API Service:

fetchDataFromServer() {
    return this.http.get();
}

In case of a request failure, it is desired to display an error modal with two buttons: "reload" and "cancel". Clicking on either button should close the modal.

One way to handle this issue inexpensively would be to simply re-trigger fetchData() from the error scenario in the component. However, handling errors at the service level would result in a cleaner solution.


I am currently investigating how to manage the button click event. By using pipe and catchError, it seemed impractical to patiently wait for the reload button click within the service method. Utilizing retryWhen seems like a potential solution, but I am struggling with the implementation.

Below is my attempt to enhance the API Service:

// The modal with the two buttons will trigger 
// - this.apiService.button$.next(true) if the user chooses to reload, or 
// - this.apiService.button$.next(false) if the user opts not to reload
button$ = new Subject<boolean>();

fetchDataFromServer() {
    return this.http.get().pipe(
        retryWhen((errors: Observable<any>) => {

            this.openErrorModal(); // a method to display the error modal

            // How can I incorporate the button$ subject here?
            // I attempted 
            // - return this.button$.pipe(), and 
            // - return errors.pipe(), 
            // but struggled to finalize the implementation

        }
    );
}

openErrorModal() {
    // Display a modal with a simple interface
}

The ultimate aim is for the component to receive the data or error regardless of the number of times the request was made. Essentially, the error modal should appear whenever the request fails, allowing the user to potentially enter into an infinite loop by choosing to reload continuously. Once the user clicks "cancel," further requests should cease.

Note: This problem has been streamlined significantly to focus solely on the core issue.

Answer №1

To achieve the desired behavior, consider modifying your design slightly. Instead of directly returning the observable from the getDataFromServer function, introduce a Subject in the middle.

This approach allows for implementing retry logic on the service in case of failures. By incorporating this as a foundational function in your services, you can easily encapsulate each call and prevent code redundancy.

The revised implementation would resemble:

tempSubject: Subject<any>;
getDataFromServer() {
  this.tempSubject = new Subject();    
  this.getDataFromServerInternal(this.tempSubject);
  return this.tempSubject;
}

private getDataFromServerInternal(sub: Subject < any > ) {
  this.httpClient
    .get()
    .subscribe(
      (res) => sub.next(res),
      (error) => {
        const confirmed = confirm(`try again? error: ${error}`);
        if (confirmed) {
          this.getDataFromServerInternal(sub);
        }
      }
    );
}

Ensure to properly complete and unsubscribe from all resources upon completion to prevent memory leaks. The method invocation from the component remains unchanged.

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

Enhancing UI-Grid: Implementing Dynamic Field Addition in the Header Name Section

https://i.sstatic.net/0jyFI.png There is a grid with a field named Users, and the requirement is to display the count of Users in the header name of a ui-grid. How can I achieve this? This snippet shows my JavaScript file code: var userCount = response.u ...

Converting Enum Values into an Array

Is there a way to extract only the values of an enum and store them in an array? For example, if we have: enum A { dog = 1, cat = 2, ant = 3 } Desired output: ["dog", "cat", "ant"] achieved by: Object.values(A) Unfor ...

The activation of Angular 2 pipe

I currently have a variety of models in my collection. When it comes to using pipes in the template, I often run into issues. <div class="card-panel" *ngFor="let card of cards | sortByType"> <card-view [card]="card" [autoupdate]="true">< ...

The password does not conform to the pattern specified in Angular CLI

I am encountering an issue with password validation. I have implemented a regex pattern like this: '(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])' and configured my ng-form field as follows: password: ['', [Validators.pattern('(?=.*[a-z])(? ...

What exactly is an npm "modular construction" and what is the process for setting it up?

I am aiming to integrate sortablejs's MultiDrag feature with Vuejs2 and Typescript. The official documentation states: MultiDrag is a plugin for SortableJS, but it may not be included in all of Sortable's builds. It comes pre-installed in the ...

Styles are not applied by Tailwind to components in the pages folder

NextJS project was already created with tailwind support, so I didn't have to set it up myself. However, when I add className to an HTML element in a component within the pages/ folder, it simply doesn't work, even though the Elements panel in D ...

Expanding the HTTP Get URL with a click in Ionic 2 and Angular 2

I recently performed a search for my ionic app, which fetches data from an api using a http get method as shown below static get parameters() { return [[Http]]; } searchRecipes(id) { var url = 'http://api.yummly.com/v1/api/recipes?_app_id=// ...

Enroll in a stream of data while iterating through a loop in an Angular application

I encounter a situation where I must subscribe to an Observable, iterate through the response, and then subscribe to another Observable using data from the initial Observable. getTasks(taskType: Observable<any>): void { taskType // Subscribing ...

Is it possible to host an Angular application on one port and a legacy application on another within a virtual machine?

I'm struggling to articulate this question properly, so please bear with me (or offer guidance) if I'm not doing it correctly. Here's the situation: In my Angular 4 app, the files are located on my host operating system (Ubuntu 16.04) and ...

How can I retrieve the document id from Firestore using Angular?

I attempted to generate an auto document ID in Firestore and retrieve the document ID in Angular 8 using the code provided. However, I am encountering an issue where I only receive the document ID after the execution has been completed. Can someone pleas ...

Incorporating properties of the parent class through Mixin techniques

I'm encountering an issue while trying to access a property from an inherited class within a mixin class BaseItem{ public id:string; constructor(id:string) { this.id =id; } } abstract class ConfigMixin<K extends BaseItem& ...

How can I bypass a unit test suite in Angular?

Is there a method to skip certain unit tests that should not be executed currently, without resorting to using fdescribe on the ones I do want to run? ...

What's the best way to set up multiple NestJS providers using information from a JSON file?

Recently diving into NestJS, I am in the process of building an application following the MVC architecture with multiple modules including: Project | +-- App.Controller +-- App.Service +-- App.Module | +-- SubModule1 | | | +-- SubModule1.C ...

Connecting parent and child entities using ngrx and ngrx/data - A comprehensive guide

I am currently developing an Angular application for a Travel Agency. On the hotel listing page, I need to display the Country and City of each hotel. The data for Country, City, and Hotel is being fetched from ngrx/data EntityService. Although my nested ...

Resolving Recursive Problems in Clarity's Tree View Design

Recently, I encountered an issue while using the Clarity Design Angular project with the Tree View recursive template provided in version 0.10.0-alpha. Check out this link for reference selectableRoot = { "@name": "A1", "selected": false, ...

Visiting route/id does not automatically trigger a template update (the address bar displays the correct route/id)

As I dive into learning Angular, I apologize in advance if my question seems basic. I am working on a simple app with a left-side panel (using Sidenav Material component) and a content area. The left-side panel displays a list of machines (MachineComponent ...

"Convert a date string to a date object using the verbose moment date

I utilized the materialize datepicker to select a date in French format. Now I need to convert this formatted date back to a date object for use in my API. Here's how I attempted to revert the date to a standard format: moment("dimanche 30 juillet 20 ...

Unable to grab hold of specific child element within parent DOM element

Important Note: Due to the complexity of the issue, the code has been abstracted for better readability Consider a parent component structure like this: <child-component></child-component> <button (click)="doSomeClick()"> Do Some Click ...

Having trouble with Angular 5 tsconfig baseURL not functioning properly?

This may appear straightforward, but I am facing difficulties with it My Angular 5 application consists of three files located as follows: app_directory/tsconfig.json app_directory/src/app/services/my-service.service.ts app_directory/src/app/main/sub1/su ...

Access the Angular Universal application through a link without specifying a port number

After creating my Angular Universal application, I'm facing an issue where I can only start it by adding the site.com:4000 port to the address. Is there a way to configure it to open without specifying a port? Any guidance on what needs to be done wou ...