"In the realm of RxJS, there are two potent events that hold the power to

In my current situation, I encountered the following scenario:

I have a service that makes Http calls to an API and requires access to user data to set the authentication header.

Below is the function that returns the observable used in the template:

getBillingReport(date: Date) {
    return this.auth.userObs$.pipe(
      switchMap((userData) => {
        const header = this.utils.createAuthHeader(userData);

        return this.http.get<BillingReport>(
          `${
            environment.apiBase
          }/reports/billing?${this.utils.monthYearQuery(date)}`,
          { headers: header }
        );
      })
    );
  }

This function takes a date parameter, so I created a Date BehaviorSubject to switchMap into this function and retrieve the data.

 billingReport$ = this.selectedDate$.pipe(
    tap(() => {
      this.loadingResults = true;
    }),
    switchMap((date) => {
      return this.reports.getBillingReport(date);
    }),
    tap(() => {
      this.loadingResults = false;
    })
  );

Everything functions correctly as the data reacts to changes in the selectedDate and the User observable. However, when attempting to implement a loading state, issues arise.

I tried using tap before the switchMap to set a boolean to true for a loading state. This approach only works if 'selectedDate$' emits (if the date changes). If the user observable emits, then only the last tap is executed, failing to create the desired loading effect.

Is there a way to ensure both events set the flag to true with this current setup? Or should I explore other solutions? Removing the switchMap from the service function may solve the problem, but every component would require something like this:

billingReport$ = this.auth.userObs$.pipe(
    tap(() => this.loadingResults = true),
    switchMap((userData) => {
      return this.selectedDate$.pipe(
        tap(() => this.loadingResults = true),
        switchMap((date) => {
          return this.reports.getBillingReport(date);
        })
      )
    }),
    tap(() => this.loadingResults = false),
  );

This approach might not be ideal since similar behavior exists in multiple components. Perhaps there's a better solution?

Note: I am utilizing the async pipe for subscription in the template.

Answer №1

If you're looking to handle loading states using combineLatest(), you can set it up in a way where the loading status is also an observable, as shown below:


setUpInput$ = input$ => concat(
  of(undefined),
  input$
).pipe(
  distinctUntilChanged()
);

newInputsCombined$ = combineLatest(
  setUpInput$(this.auth.userObs$),
  setUpInput$(selectedDate$)
).pipe(
  filter(
    ([userObs, selectedDate]) => userObs !== undefined && selectedDate !== undefined
  )
);

dataRetrieval$ = newInputsCombined$.pipe(
  switchMap(([userData, date])) => this.http.get<RelatorioCobranca>(
    `${environment.apiBase}/relatorios/cobrancas?${this.utils.monthYearQuery(date)}`,
    {
      headers: this.utils.createAuthHeader(userData)
    }
  ))
);

loadingStatus$: Observable<boolean> = merge(
  of(false),
  newInputsCombined$.pipe(
    mapTo(true)
  ),
  dataRetrieval$.pipe(
    mapTo(false)
  )
).pipe(
  shareReplay(1)
);

By setting it up this way, the loadingStatus$ will be true until dataRetrieval$ emits a result when both user data and a date are available.

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

Utilizing combinedReducers will not prompt a re-render when dispatching actions

When I refrain from using combineReducers: const store = createStore<StoreState,any,any,any>(pointReducer, { points: 1, languageName: 'Points', }); function tick() { store.dispatch(gameTick()); requestAnimationFrame(tick) ...

Dynamically importing TypeScript interfaces for React code splitting

Is it possible to utilize dynamic import('path') for an exported interface? ...

Developing Angular dynamic components recursively can enhance the flexibility and inter

My goal is to construct a flexible component based on a Config. This component will parse the config recursively and generate the necessary components. However, an issue arises where the ngAfterViewInit() method is only being called twice. @Component({ ...

Error: The npm-link library encountered an invalid hook call

Problem Description: I am working on developing a package named eformless. To set up the package, I utilized CRA to create a directory named sandbox where I linked the package. However, I keep encountering an error when attempting to launch the sand ...

Steps for selectively targeting and updating a group of properties in a TypeScript class

Is there a way to consolidate this code into one function that can handle all the tasks below? I'm adding more text here to meet the requirements and hoping for a solution. Thank you! TypeScript is an amazing language that differs slightly from JavaS ...

Definition for a function within a specific namespace that returns the specified object

Seeking to define the type of a function within a namespace (L.DomEvent.on(e)) that returns this, I encountered an issue with my JavaScript source code: L.DomEvent = { // @function on(el: HTMLElement, eventMap: Object, context?: Object): this on: ...

having difficulty applying a border to the popup modal

Currently, I am utilizing a Popup modal component provided by the reactjs-popup library. export default () => ( <Popup trigger={<button className="button"> Guide </button>} modal nested > {(close: any) =&g ...

Developing with Ionic 2 allows you to efficiently run a background service using Cordova

I am currently using Ionic 2 and I have a requirement for my app to perform certain tasks even when it is closed, similar to how Gmail continues to provide notifications all the time. After some research, I came across this documentation: https://ionicfr ...

Nested component in reactive forms not functioning as expected

I've been experimenting with creating nested reactive form components. Specifically, I'm working on a reusable input component for my app within a reactive form. How can I dynamically communicate with nested components in Reactive forms? Despite ...

Using Vue in conjunction with TypeScript and CSS modules

I am facing an issue with my SFC (single file vue component) that utilizes TypeScript, render functions, and CSS modules. <script lang="ts"> import Vue from 'vue'; export default Vue.extend({ props: { mode: { type: String, ...

Struggling to access the 'payload' property of an undefined object? In TypeScript, you can easily bind and access JSON objects using *ngFor directive

I've been attempting to retrieve highscores from the server using node angular and making an http request. Although I successfully obtain the JSON file from the server, I am encountering difficulty accessing the fields for processing in the *ngFor lo ...

Building powerful web applications using Angular 2 CLI and Express.js

I am exploring the idea of setting up Express.js with Node.js as the server for my Angular 2 project. I have been following tutorials on integrating Express.js with the Angular CLI, such as this and this, but so far, I have not had much success. If anyon ...

Setting a value to an optional property of an inherited type is a simple task that can

export interface CgiConfiguration { name: string, value?: string } export interface CgiConfigurationsMap { [configurationName: string]: CgiConfiguration } const createCGI = <T extends CgiConfigurationsMap>(configurations: T) => configur ...

Tips for importing a package in Angular 2 with Visual Studio 2015

After running npm install --save camelCase, I have successfully installed the package. Now, I am looking to utilize it in my project along with TypeScript version 2.0.3. In order to import the package, I added the following line: import * as camelcase ...

Error: Failed to fetch the data from the Firebase database

I have recently added an edit button to my product list, but when I click on it, the form page opens with no data populated. Upon debugging in my product.service.ts file, I noticed that it outputs null when using console.log(p). I believe this is where the ...

Encountering an error in resolving a dependency while attempting to run 'npm

I'm working with Angular version 13 at the moment. Encountered some errors when trying to execute the npm install command. Any suggestions on how to resolve these issues? > npm install npm ERR! code ERESOLVE npm ERR! ERESOLVE could not solve npm ...

Personalize ng-multiselect-dropdown in order to establish connections with multiple model fields

Is there a way to customize the ng-multiselect-dropdown control in order to include a CodeField? This would be helpful for persisting model values during selection. ...

"Utilizing the power of Angular 6's JSON pipe

Looking for a well-structured formatted JSON, but all I get is confusion and this strange image: Does anyone have any insights on what might be causing the issue? HTML <span style="font-weight: 500;">Payload Data: </span> <pre><co ...

Enhancing search capabilities in Angular 8.1.2 by filtering nested objects

I am in need of a filter logic similar to the one used in the example posted on this older post, but tailored for a more recent version of Angular. The filtering example provided in the older post seems to fit my requirements perfectly, especially with ne ...

Using Typescript with Styled-Components and Styled-System: Unable to find a matching overload for this function call

Encountering the infamous "No overload matches this call" error when using a combination of Typescript, Styled-Components, and Styled-System. I've come across solutions that suggest passing a generic type/interface to the styled component, like the o ...