Is it possible for Angular to detect when an rxjs observable subscription begins?

Is it possible to detect the beginning of a subscription to an RxJS observable within the pipe?

I am looking to activate a loading indicator when a HTTP observable is subscribed (which will be destroyed once the response has been finalized).

Alternatively, do I need to create a wrapper observable for this task?

Answer №1

Depending on the version of RxJS you have, there are different ways to handle loading flags. For RxJS versions prior to 7.3, you can utilize the defer() method:

defer(() => {
  loadingIndicator = true;
  return this.http.sendRequest().pipe(
    finalize(() => loadingIndicator = false),
  );
});

If you are using RxJS 7.3 or newer, you can make use of new event handlers in the tap() operator:

this.http.sendRequest().pipe(
  tap({
    subscribe: () => loadingFlag = true,
    finalize: () => loadingFlag = false,
  }),
);

Answer №2

To ensure that each subscription to an HTTP observable triggers a new HTTP call, it is recommended to set a flag outside of the pipe operation as shown in this example.

fetchData(){
  isLoading=true;
  return this.http.makeRequest().pipe(finalize(()=>isLoading=false));
}

If you are interested in tracking the subscriber count (which always resets to 0 after each request due to finalization of the HTTP observable), consider exploring the implementation of refCount() and share() operators which internally manage subscriber counts.

Edit:

You can streamline the process of setting the flag by using a dummy observable as an entry point, like so:

fetchData(){
  return of(null).pipe(
      tap(()=>isLoading=true),
      switchMapTo(this.http.makeRequest()),
      finalize(()=>isLoading=false)
  )
}

Answer №3

Why not create an observable to track the state of your request instead of setting an indicator as a side effect in your stream?

readonly makeRequestSubject = new Subject<RequestParams>();
readonly request$ = makeRequestSubject.pipe(
  switchMap(params => this.doRequest(params).pipe(
    map(result => ({ params, result,  state: 'complete' })),
    catchError(error => ({ error, params, state: 'error' }))
    startWith({ params, state: 'loading' })
  ),
  startWith({ state: 'notstarted' }),
  shareReplay(1)
);
readonly isLoading$ = this.request.pipe(map(x => x === 'loading'), distinctUntilChanged());
readonly results$ = this.request.pipe(map(x => x === 'complete' ? x.results : []));
  1. Consider returning an observable from a method as a stream for dependents to subscribe and unsubscribe as needed, rather than using multiple fields. Call next() on makeRequestSubject when making a new request.
  2. The outer startWith emits first and can provide helpful instructions if no requests have been made, especially in UI scenarios.
  3. Initiate the request in a switchMap to interrupt prior calls that are incomplete with successive ones.
  4. The inner startWith operator emits first unless the request is immediate.
  5. Use catchError for handling errors beyond setting loading indicators.
  6. You can directly subscribe to request$ or use isLoading$ and results$. It's best to keep the model in sync with UI bindings without creating extra observables.
  7. Including params can be beneficial for UI purposes.

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

MongoDB find query did not utilize the index

I'm currently trying to implement full text search on my MongoDb database using TypeScript and Node.js. However, I've encountered an issue during unit testing where my search for a specific text string in the index keeps failing. The index is cre ...

The Angular2 application encountered a 404 file not found error while trying to read a Const from a ts

Recently I started working with angular2 and encountered a problem when trying to access constant values from an external .ts file using the following code: import {apis} from '../constants/apis'; The content of the constants/apis.ts file is as ...

Mongoose encountered an error when attempting to cast the value "ObjectID" to an ObjectId at the specified path "red.s1"

My Mongoose schema is structured as follows: const gameSchema = new Schema({ matchNumber: { type: Number, required: [true, 'A match must have a number!'], unique: true }, red: { s1: { type: ...

Whenever I try to utilize async with React.FC in my React component, a TypeScript error is thrown

I am currently working on a React functional component called DashboardPage that utilizes async/await for fetching data, but I am running into a TypeScript error. The specific error message reads: 'Type '({ params }: DashboardPageProps) => Pro ...

Creating a mongoDB query that matches elements in an array of subdocuments with elements in a Typescript Array

In my database, I have stored various Events using mongoDB. Each event comes with multiple fields, including an array of genres, which consists of subdocuments like {genre and subGenre}. For instance, an event could be classified as {genre: "music", subGe ...

Troubleshooting guide: Issues with compatibility between Angular 5 and Bootstrap 4

Upon creating a fresh Angular 5 project, I decided to integrate Bootstrap 4.0.0 using the guidelines provided on the Angular CLI GitHub page. Following the instructions, I utilized 'npm install bootstrap' to incorporate Bootstrap into my project. ...

A data type representing a specific category rather than a specific object

My job involves working with Sequalize models, which are essentially classes. Upon registration, these models are populated with some data that needs to be stored. To accomplish this, I store them in a list. However, when retrieving a model into a variab ...

Tips on saving stimulsoft report js onto a server using Angular

I am working on a report designer component and have assigned a method to the onSaveReport event. However, I am encountering an issue where the member of my component is showing as undefined. options: any; designer: any; public document: Report ...

Understanding the Typescript definitions for different event types in React

How do I properly define the type for React events? In the beginning, I simply used any to keep things simple. However, I am now trying to improve my code and eliminate the use of any altogether. Here is a basic example: export interface LoginProps { l ...

Using AMCharts with Angular but encountering an issue where there is no data present in the array within the AM

Utilizing a chart from AMCharts within an Angular component has raised some challenges. Although a data array is successfully passed into the component template, it appears empty when accessed inside the AMCharts code. This puzzling issue occurs in the p ...

What is the reason for the 'ng version' command returning a blank line as a response?

... Along with all other ng commands. Greetings! Recently, I decided to reinstall node.js due to a persistent issue, however, the problem still remains. https://i.sstatic.net/BZpkIszu.png After the reinstallation, I executed the initial commands. Npm i ...

Is it necessary to upload items individually using Angular 7 and Asp.net?

I'm encountering an issue where I am trying to send objects to my server, but the objects received have null values. Here is a snippet of the backend code: // Signature public IActionResult Save(string num, string pat, string token, [FromBody]DataC ...

Formatting the Return Values of Ionic Select

Having an issue with Ionic 3. Using an <ion-select> element with ngModel="x". When attempting to display the value in the console, it shows with extra spaces and line breaks. I tried replacing line breaks with 'e' and spaces with 'a&ap ...

The Discordjs v13.1 bot is having trouble generating audio from an mp3 file

Having an issue with my bot playing an mp3 file. It successfully joins the voice chat and starts playing, but there is no audio output. The bot icon lights up green indicating it's playing, but no sound is heard. Here's the code snippet: awa ...

What is the best way to include a TypeScript property within a JavaScript code?

I am currently attempting to utilize a typescript property known as this.data with the assistance of the executescript() method from the InAppBrowser plugin. However, I am encountering an issue where the property is returning undefined instead of 'tes ...

Verify whether the value of the Reactive form has been modified from its initial state

I am currently dealing with a reactive form that has 3 controls, and I need to detect any changes made to the form. I have implemented a method for detecting value changes in the form and subscribed to it. However, I am facing an issue where the event is b ...

Why injecting a service into a class in Angular may not be the best practice and what alternatives you should consider instead

Trying to access a Service from a Class in Angular has been a challenge. While many sources suggest it's not the best practice, I'm struggling to find an alternative solution for my specific case. This scenario is a simplified version of my real ...

Utilize an array of JSON objects to populate an array of interfaces in Angular/Typescript

I am currently facing a dilemma - my code is functioning without any errors when executed, but my text editor is flagging an issue stating that the property 'categories' does not exist on type 'CategoryInterface[]' (specifically on the ...

Most effective method for *overriding* TypeScript types from third party libraries in the node_modules directory

Often, third-party type definitions included in a dedicated @types/* package or alongside an npm package are discovered to be incomplete or incompatible with new dependencies. Thus, I am searching for an easy way to override the types specified in node_mo ...

Ways to determine if a specified character sequence is present in an Enumerator?

One of my coding dilemmas involves an enum that looks like this: export enum someEnum { None = <any>'', value1 = <any>'value1', value2 = <any>'value2', value3 = <any>'value3' ...