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

Chrome reports "404 Not Found error: Cannot GET /" while using Angular 4 with Observable functions

I recently implemented observable data in my service, and it significantly improved the functionality of the application. https://i.sstatic.net/9h0KH.jpg This is an overview of my Service: import { Injectable } from '@angular/core'; import { H ...

When an event is triggered in Angular Component, the object is not properly defined in the handler causing errors

While experimenting with createjs and angular, I encountered an issue when trying to update my stage after an image loads. It seems like there might be a problem related to Angular in this situation. Upon completion of the load event on the Bitmap object a ...

Developing an object using class and generic features in Typescript

I am currently working on creating a function or method that can generate sorting options from an array. One example is when using Mikro-ORM, where there is a type called FindOptions<T> that can be filled with the desired sorting order for database q ...

The attribute 'name' cannot be found within the class 'MyComponent'

I'm a beginner in Angular2 and I have no previous knowledge of version 1. Can you help me understand why this error is occurring and guide me on how to fix it? import { Component } from 'angular2/core'; @Component ({ selector: 'my- ...

Exploring Angular 4: Leveraging mockRespond in Conjunction with RxJS Observables

I recently completed the development of an application that is functioning smoothly. Now, I am in the process of creating a test for it. The core functionality involves fetching items from an API backend: export class CatfactService { constructor(p ...

Adjusting box width based on device type: desktop and mobile

I'm currently working on a form that includes several mat-form-fields. I have set the width of these items to 750px, but this does not work well for mobile devices. I am trying to figure out how to make the form or mat-form-field automatically adjust ...

Steps to Validate a Form: To allow the submit button to be enabled only when all input fields are filled out; if any field is left empty,

Is it possible to enable the send offer button only after both input boxes are filled? I'm sharing my code base with you for reference. Please review the code and make necessary modifications on stackblitz 1. example-dialog.component.html <form ...

Error occurs in Typescript when attempting to store data in a record using a pointer

When working with nodes and organizing them into a tree structure, I encounter an issue: This is the definition of the interface: interface IDataObj { children: IDataObj[], frontmatter : { type: string, title: string, path: string}, name: str ...

Issue with saving date values accurately in Nestjs/Prisma

After logging the response body before saving it to the database, I noticed that the shape is correct. Here's what it looks like: //console.log response body CreateOpenHourDto { day: 'WEDNESDAY', startTime: 1663858800000, endTime: 16638786 ...

Uncovering a commitment to reveal the valuable information within

Whenever my Spring Boot back-end responds to front-end requests, it structures the data like this: { "timestamp":[2022,6,16], "status":"OK", "data": { "products": [{"product ...

Compiling TypeScript: Using the `as` operator to convert and then destructure an array results in a compilation error, requiring an

I am currently utilizing TypeScript version 2.9.2. There is a static method in a third-party library called URI.js, which is declared as follows: joinPaths(...paths: (string | URI)[]): URI; I have a variable named urlPaths that is defined as urlPaths: s ...

I am having trouble locating my source code within the Typescript module

My issue lies with a file called Server.js, which holds the code for export class Program and includes <reference path='mscorlib.ts'/>. However, when I compile it using the command: tsc -t ES5 Server.ts --module commonjs --out Server.js T ...

The template is displaying the string as "[object Object]"

I've implemented code in my ngOnInit function to fetch the translation for a specific text. The following function is being called: async getEmailTranslation() { const email$ = this.translate.get('SUPPORT_TRANSLATE.EMAIL'); this.emai ...

Authenticate users by accessing their login information stored in a MongoDB database using Node.js and Express

I have been experimenting with various techniques, and incorporating Passport middleware has brought me the closest to achieving this task. I suspect there might be a final step missing for everything to function correctly, as I am not encountering any err ...

Determine the data type of an index within an array declaration

Imagine we have the following array literal: const list = ['foo', 'bar', 'baz'] as const; We are attempting to create a type that represents potential indices of this array. This is what we tried: const list = ['foo&ap ...

A tutorial on implementing a "Back to Top" button that appears dynamically while scrolling in Angular

I've developed a scroll-to-top feature for my Angular project, but I'm facing an issue. The scroll icon appears immediately upon page load instead of only showing after the user scrolls down. Any ideas or suggestions on how to achieve this? Here ...

Utilizing handpicked information in Angular: A beginner's guide

Being new to Angular and programming in general, I am currently navigating through the intricacies of Angular and could use some guidance on utilizing selected data. For instance, I would like to use a personnel number view image here and send it to the b ...

How can ng-content be used to adjust the displayed content in Angular?

I am working with two components: hostComponent and textComponent. My goal is to project content inside textContent and make modifications based on other input properties. <app-text-component characterCount='5'> <span> Hello World ...

What is the method for installing TypeScript declarations for packages with scopes or namespaces using @types?

My current challenge involves the use of TypeScript and my desire to utilize a scoped package such as @foo/bar or @babel/core that does not include its own type declarations. My attempted solution so far has been to execute the following command: npm ins ...

Guide on utilizing TypeScript interfaces or types in JavaScript functions with vscode and jsdocs

Is there a way to utilize types or interfaces to provide intellisense for entire functions or object literals, rather than just function parameters or inline @type's? For example: type TFunc = ( x: number ) => boolean; /** * @implements {TFunc} ...