Enhancing rxjs observables with pre- and post-actions (such as displaying or hiding a loading screen)

I'm attempting to create a function that wraps a given Observable and adds a loading screen to it.
The function

function addLoadingScreen<T>(obs$: Observable<T>): Observable<T>
should function like this:

  1. Show the loading screen.
  2. Execute the observable received as a parameter.
  3. Hide the loading screen after all values are emitted.

Initially, my implementation idea was:

function addLoadingScreen<T>(obs$: Observable<T>): Observable<T> {
  return of(null).pipe(
    tap(() => console.log("show loading screen")),
    switchMap(() => obs$),
    finalize(() => console.log("hide loading screen"))
  );
}

However, when I chain other operators to the result of this function, the "hide loading screen" message is executed after those chains, not after the original observable finishes.

Here's an example: https://stackblitz.com/edit/rxjs-wrapping-observable

The result in the console above shows:

show loading screen
im reducing
im reducing
reducing finished so loading screen should be hidden
the result is 6
hide loading screen

What I'm striving for is:

show loading screen
im reducing
im reducing
hide loading screen
reducing finished so loading screen should be hidden
the result is 6

Answer №1

One reason for this behavior is that the finalize function is executed after the teardown process, as explained in detail in this GitHub Issue. This means that even if you place finalize before other operators like reduce or mergeMap, it will still be the last to run during the cleanup.

To address your issue, an alternative solution involves using the tap operator in the following way:

function wrapWithLoadingScreen<T>(obs$: Observable<T>): Observable<T> {
  return of(null).pipe(
    tap(() => console.log("show loading screen")),
    switchMap(() => obs$),
    tap(
      () => {},
      () => console.log("hide loading screen"),
      () => console.log("hide loading screen")
    ),
  );
}

In addition to handling the next callback, you can also utilize the error and complete callbacks with the tap operator. For more insights on these error and complete callbacks, refer to the RxJS Tap Doc.

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

Using ExpressJS with Typescript and NodeJS to serve static files is a powerful combination

Having trouble serving a static file uploaded using ExpressJS and NodeJS with Typescript as I'm encountering a 404 error. The file I need to access is located at ./src/data/uploads/test.txt, and I am attempting to reach it directly from a web browser ...

What causes parameters to be undefined when making a DELETE request in my Next.js application running on version 14.1.4?

I am encountering an issue with my DELETE mapping export async function DELETE({params} : {params: {id: string}}) { try { const loanToDelete = await prisma.loan.findUnique({ where: { id: parseInt(params.id) } }) if (!loanToDelete ...

Having trouble fixing NPM TypeScript index.ts package export issue?

I've recently developed a typescript validation library that can be found here. Right now, I'm working on putting together a live demo using Stackblitz, which you can access here. However, I'm encountering an issue with the following import ...

What sets apart Record<key, type> from [key: string]: type?

Can someone explain the distinction between Record<key, type> and [key: string]: type? Are they interchangeable? Which one offers more flexibility and type safety? I have come across a situation where both were used interchangeably. Is there a prefe ...

The TypeScript compiler is unable to locate the module react-scripts within the lerna webpack configuration

Recently, I've been working on setting up a new project using lerna, react-scripts, webpack, and sass. Here is my current directory structure: myApp /packages /myReactApp -> a react create app application /tsconfig.json /package ...

Setting up raw-loader in Angular 7 for loading text files

I am struggling to implement a raw-loader with my Angular 7 in order to import text files into my TypeScript source code. Despite spending several hours researching and attempting various methods, I have been unsuccessful in getting it to work. My journey ...

Is tsconfig.json Utilized by Gatsby When Using Typescript?

Many blog posts and the example on Gatsby JS's website demonstrate the use of a tsconfig.json file alongside the gatsby-plugin-typescript for TypeScript support in Gatsby. However, it seems like the tsconfig.json file is not actually utilized for conf ...

Take a look at the browser's view

Are there any methods to monitor changes in the browser window using an Observable, such as rxJS or a similar tool? I am interested in triggering an action whenever the browser window is resized. ...

Finding a solution for duplicate date selections in NextJS using react-calendar

I am currently working on a calendar component using NextJS, typescript, tailwindcss, and the react-calendar library. I have encountered an issue with duplicate dates appearing in the calendar when selecting a date range. Although I have managed to handle ...

Attempting to create a bar graph using Angular framework

I'm currently working on developing a dashboard in Angular that includes a chart feature. Within my Firebase Firestore database, I have two collections: 'mechanicQualifications' and 'mecanicos'. The 'mechanicQualifications&apo ...

Learn how to efficiently disable or enable a button in Angular depending on the selected radio button

In order to disable the button when the remarks are marked as failed. Here is an example scenario: Imagine there is an array containing two to four items. First example: ITEM 1 -> FAILED -> Remarks (required) ITEM 2 -> FAILED -> Remarks (r ...

Guide on how to include jquery-ui css file in Vue3

I am new to TypeScript and VueJs. Recently, I decided to incorporate jquery-ui into my project using Vue3, TypeScript, and Electron. After some trial and error, I was able to successfully set up the environment. However, when I attempted to use the jquery ...

Obtain the ViewContainerRef object from the Component

Looking to create nested components in Angular 4? This is the Chooser Component import {InputComponent} from './input/input.component' import {BlockComponent} from './block/block.component' export const FormChooser = { Block: Block ...

How can I exclude the 'node_modules' directory but still include specific subfiles in the tsconfig file for TypeScript?

My tsconfig file is structured as follows: { "compileOnSave": false, "compilerOptions": { "module": "es2015", "target": "es2015", "sourceMap": true, "jsx": "react", "allowSyntheticDefaultImports": true, "noImplicitAny": false, ...

How to remove the border of the MUI Select Component in React JS after it has been clicked on

I am struggling to find the proper CSS code to remove the blue border from Select in MUI after clicking on it. Even though I managed to remove the default border, the blue one still persists as shown in this sandbox example (https://codesandbox.io/s/autumn ...

Tips for addressing the error "Ensure each child in a list has a distinctive 'key' prop" in a React function using TypeScript

Encountered the following warning: Warning: Each child in a list should have a unique "key" prop. Inspect the render method of TabContext. Refer to https://reactjs.org/link/warning-keys for more details. in TabForGroupInList (at Product.tsx:148) ...

AngularJS providers $get method does not seem to recognize the interface specified

Hey there! I've been working on implementing a state provider in TypeScript, but I seem to be having some issues with the reference provider closure. When trying to migrate my JavaScript code to TypeScript, I encountered an error stating that the &apo ...

Avoiding the insertion of duplicates in Angular 2 with Observables

My current issue involves a growing array each time I submit a post. It seems like the problem lies within the second observable where the user object gets updated with a new timestamp after each post submission. I have attempted to prevent duplicate entr ...

`Is it possible to integrate npm libraries with typescript and ES6?`

I am looking to focus on using ES6 as the output for a node server-side app that I plan to run on the cutting-edge iojs distribution, which hopefully has support for the latest ES6 syntax. However, I'm unsure about how to integrate standard NPM libra ...

Issue: Unable to assign type 'FormDataEntryValue' to type 'string'. Type 'File' cannot be assigned to type 'string'

After retrieving data from the formData, I need to pass it to a function for sending an email. Error: The error message states that 'FormDataEntryValue' is not compatible with type 'string | null'.ts(2322) definitions.ts(119, 3): The e ...