RxJS pipe operation ignoring observable

Currently, I am in the process of transitioning an app from Promises to RxJS and I could use some guidance on whether I am heading in the right direction.

Situation: I have a ModalComponent that appears when an HTTP request is sent and disappears once the response is received. Here's what I'm doing:

public post(uri: string, body: object, showLoading: boolean = true, params: object = {}): Observable<any> {
if (showLoading) {
  this.toggleModal('open');
}

return this.http.post(
  this.createUrl(uri),
  body,
  this.createOptionsWrapper(params)
)
.pipe(
  this.toggleModal('close'),
  catchError(err => this.handleError(err))
);

}

toggleModal() takes one parameter and controls the opening or closing of the Modal based on that. I am aware that pipeable Operators should return an OperatorFunction type. What do you think would be the most appropriate RxJS Operator for my scenario, where I don't need to manipulate the Observable itself but simply want to make it pipeable so it follows a specific sequence? Would it be beneficial to create a custom Operator for this purpose? Keep in mind that the Observable being returned here will be piped elsewhere whenever the service is injected.

Answer №1

In my opinion, using the finalize operator would be the most suitable approach in this scenario. It is triggered when the source completes or encounters an error and does not alter the output from the observable.

public post(
  uri: string, 
  body: object, 
  showLoading: boolean = true,
  params: object = {}
): Observable<any> {
  if (showLoading) {
    this.toggleModal('open');
  }

  return this.http.post(
    this.createUrl(uri),
    body,
    this.createOptionsWrapper(params)
  ).pipe(
    finalize(() => {
      if (showLoading) {
        this.toggleModal('close');
      }
    }),
    catchError(err => this.handleError(err))
  );
}

Answer №2

Agreeing with Michael D, I believe that using the finalize operator is essential in this scenario. However, I also suggest wrapping it in a defer statement:

public post(uri: string, body: object, showLoading: boolean = true, params: object = {}): Observable<any> {
  return defer(() => {
    if (showLoading) {
      this.toggleModal('open');
    }

    return this.http.post(
      this.createUrl(uri),
      body,
      this.createOptionsWrapper(params)
    ).pipe(
      finalize(() => this.toggleModal('close')),
      catchError(err => this.handleError(err))
    );
  });
}

It's important to note that observables are designed to do nothing until they are subscribed to. So, by utilizing defer, you avoid situations where actions occur prematurely:

let save$ = this.service.post(...)
if (id) {
   save$ = this.service.put(...)
}
save$.subscribe();

Without defer, the modal could potentially be toggled before subscription. By incorporating defer, you ensure that actions are performed only when necessary, preventing any unexpected behavior.

Answer №3

When working with responses and you prefer not to alter the results, consider using the tap operator.

return this.http.post(
  this.createUrl(uri),
  body,
  this.createOptionsWrapper(params)
)
.pipe(
      tap( () => this.toggleModal('close') ),
      catchError(err => this.handleError(err))
);

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

Retrieving latitude and longitude from place id in an Angular Google Maps component

Currently utilizing the google-maps component to extract latitude and longitude from Google Maps prediction data. Additionally, I have integrated a search bar using google-maps component. I have successfully implemented a search bar with ngx-google-places ...

What is the process for subscribing to the output of a flatMap operation?

Is there a way to subscribe to the result of flatMap in this code block? timer(0, 2000) .pipe( flatMap(() => this.scannerService.scan(this.scanType)), takeWhile(res => res.errorDesc !== "SUCCESS") ) .subscrib ...

How can we use tsyringe (a dependency injection library) to resolve classes with dependencies?

I seem to be struggling with understanding how TSyringe handles classes with dependencies. To illustrate my issue, I have created a simple example. In my index.tsx file, following the documentation, I import reflect-metadata. When injecting a singleton cl ...

Cannot assign Angular 4 RequestOptions object to post method parameter

I'm having trouble with these codes. Initially, I created a header using the code block below: headers.append("Authorization", btoa(username + ":" + password)); var requestOptions = new RequestOptions({ headers: headers }); However, when I tried to ...

Uncover the solution to eliminating webpack warnings associated with incorporating the winston logger by utilizing the ContextReplacementPlugin

When running webpack on a project that includes the winston package, several warnings are generated. This is because webpack automatically includes non-javascript files due to a lazy-loading mechanism in a dependency called logform. The issue arises when ...

Nebular specializes in crafting personalized registration solutions

I am currently working on a custom registration form that is different from the standard Nebular registration. Due to the custom form validation I have implemented, the standard registration system no longer functions as intended for me. I believe I need t ...

Obtain item from DataSource in Angular's MatTable

In my transaction-history.component.ts file, I have implemented a material data table that fetches data from a query to display it. Here is the code snippet: import { Component, OnInit } from '@angular/core'; import { Transaction } from '.. ...

Creating an Angular project that functions as a library and integrating it into a JavaScript project: a step-by-step guide

Is it feasible to create an Angular library and integrate it into a JavaScript project in a similar manner as depicted in the image below? The project structure shows trading-vue.min.js being used as an Angular library. Can this be done this way or is th ...

Is there a way to change a typescript enum value into a string format?

I'm working with enums in TypeScript and I need to convert the enum value to a string for passing it to an API endpoint. Can someone please guide me on how to achieve this? Thanks. enum RecordStatus { CancelledClosed = 102830004, Completed = ...

Transferring data types to a component and then sending it to a factory

I have been grappling with creating a factory method using Angular 2 and TypeScript. However, my attempts have hit a roadblock as the TSC compiler keeps throwing an unexpected error: error TS1005: ',' expected. The issue arises when I try to pa ...

Angular Image/Video Preview: Enhance Your Visual Content Display

Is there a way to preview both images and videos when uploading files in Angular? I have successfully implemented image preview but need help with video preview. Check out the stackblitz link below for reference: CLICK HERE CODE onSelectFile(ev ...

When using TypeScript's array intersection type, properties are not accessible when using methods like Array.forEach or Array.some. However, they can be accessed within a for loop

It was challenging to search for this problem because I may not have the correct technical terms, but I hope my example can help clarify it. Background: I am using query data selectors in react-query to preprocess query results and add some properties tha ...

Is it possible to utilize an XML format for translation files instead of JSON in React Native?

I'm in the process of creating a react native application using the react i18next library. For translations, I've utilized XML format in android for native development. In react native, is it possible to use XML format for translation files inste ...

Where can I find the Cypress.json file for Angular integration with Cypress using Cucumber?

We are currently transitioning from Protractor to Cypress utilizing Cucumber with the help of cypress-cucumber-preprocessor. While searching for Angular documentation on this setup, including resources like , all references lead to an automatically generat ...

Exploring TypeScript's Conditional Types

Consider this scenario: type TypeMapping = { Boolean: boolean, String: string, Number: number, ArrayOfString: Array<string>, ArrayOfBoolean: Array<boolean> } export interface ElemType { foo: keyof TypeMapping, default: valueof T ...

What is the best way to handle asynchronous actions while initializing a database in Next.js?

My goal is to create tables during the database initialization stage with a structure like this: CREATE TABLE IF NOT EXISTS users ( "id" SERIAL PRIMARY KEY, "created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "name&quo ...

Guide on integrating Amazon S3 within a NodeJS application

Currently, I am attempting to utilize Amazon S3 for uploading and downloading images and videos within my locally running NodeJS application. However, the abundance of code snippets and various credential management methods available online has left me fee ...

What is the best way to filter and sort a nested tree Array in javascript?

Looking to filter and sort a nested tree object for a menu If the status for sorting and filtering is true, how do I proceed? const items = [{ name: "a1", id: 1, sort: 1, status: true, children: [{ name: "a2", id: 2, ...

Design: Seeking a layout feature where one cell in a row can be larger than the other cells

To better illustrate my goal, refer to this image: Desired Output <\b> Currently, I'm achieving this: current output Imagine 7 rows of data with two columns each. The issue arises in row 1, column 2 where the control needs to span 5 rows v ...

Discover the accurate `keyof` for a nested map in TypeScript

Here is the code snippet I'm working on: const functions={ top1: { f1: () => 'string', f2: (b: boolean, n: number) => 1 }, top2: { f3: (b: boolean) => b } } I am looking to define an apply f ...