Which is the optimal choice: subscribing from within a subscription or incorporating rxjs concat with tap?

After storing data in the backend, I proceed to retrieve all reserved data for that specific item.
It is crucial that the data retrieval happens only after the reservation process to ensure its inclusion.

Presented with two possible solutions, I am contemplating which one is superior and whether utilizing concat with tap provides any advantages in this scenario:

Using subscription inside another subscription:

...
this.reserveDataItem();
...

reserveDataItem(){
   this.myService.reserveData(this.selectedData).subscribe(res => {
     if (res.status == 'SUCCESS'){
       ...logSuccessMessagesAndOtherStuff
     }
     this.getReservedDataItemsId();
   });
 }


getReservedDataItemsId(){
   this.myService.getReservedDataItemsForRequestId(this.requestId).subscribe(res => {
     if (res.status == 'SUCCESS'){
       ..doStuffWithDataItems
     }
   });
 }

Implementing concat with tap:
I opted for tap due to difficulties in handling multiple return types within a single subscription
and thus, I am curious about any potential benefits of using this method..

...
concat(this.reserveDataItem(), this.getReservedDataItemsId())
   .subscribe();
...

reserveDataItem(): Observable<ApiResponseDto<any>>{
  return this.myService.reserveData(this.selectedData).pipe(
    tap(res => {
      if (res.status == 'SUCCESS'){
        ...logSuccessMessagesAndOtherStuff
      }
    })
  )
 }


getReservedDataItemsId():Observable<ApiResponseDto<DataItemDto[]>>{
   return this.myService.getReservedDataItemsForRequestId(this.requestId).pipe(
    tap(res => {
       if (res.status == 'SUCCESS'){
         ..doStuffWithDataItems
       }
     })
  )
 }

Answer №1

From what I gather from your inquiry:

After saving data on the backend (first Observable), you receive a response once the save operation is completed. Regardless of the response status, you intend to make another request following the completion of the first Observable. Only after the initial task is finished do you wish to retrieve this data.

If your reserveData method involves making a single HTTP request, my suggestion would be to employ switchMap:

"When utilizing switchMap, each inner subscription concludes when the source emits, allowing only one active inner subscription."
(from https://www.learnrxjs.io/)

Below is a simplified version of how I would address the problem:

myObs = new Observable((observer) => {
    observer.next({status: 'SUCCESS'});
    observer.complete();
});

myObs2 = new Observable((observer) => {
    observer.next({status: 'SUCCESS'});
    observer.complete();
});

this.myObs.pipe(
  switchMap((resp) => {
    if (resp.status === 'SUCCESS') ...logSuccessMessagesAndOtherStuff;
    return this.myObs2;
  })
).subscribe(resp => {
  if (resp.status === 'SUCCESS') ...doStuffWithDataItems;
})

I also have a related question that might offer some insight into your situation. Considering that an Http request/response yields 'only the last notification (the result from the HTTP request),' it seems unnecessary to utilize mergeMap or concatMap (assuming your reserveData method primarily makes one HTTP request and returns a response).

Answer №2

Switch to using forkJoin instead :

    const response1 = this.myService.reserveData(this.selectedData);
    const response2 = this.myService.getReservedDataItemsForRequestId(this.requestId);
    
    fetchData(): Observable<any> {
      return forkJoin([response1, response2]);
    }
    
    this.fetchData().subscribe(result => {
       //...handleSuccessMessagesAndMore result[0]
       //..processDataItems result[1]
    }, error => {
       console.log(error);
    });

Answer №3

Here is a way to structure your code without nesting subscriptions:

this.myService.reserveData(this.selectedData).pipe(
  mergeMap(res => {
    if (res.status == 'SUCCESS'){
      ...logSuccessMessagesAndOtherStuff
    }
    return this.myService.getReservedDataItemsForRequestId(this.requestId)
  })
).subscribe(res => {
  if (res.status == 'SUCCESS'){
    ..doStuffWithDataItems
  }
});

It's beneficial to avoid nesting subscriptions to prevent complex structures in the code. By using operators like map and filter, you can easily enhance your data pipeline with additional transformations or filters.

For instance, you can filter out unsuccessful results before processing them further as shown in the above code snippet.

this.myService.reserveData(this.selectedData).pipe(
  mergeMap(res => {
    if (res.status == 'SUCCESS'){
      ...logSuccessMessagesAndOtherStuff
    }
    return this.myService.getReservedDataItemsForRequestId(this.requestId)
  }),
  filter(res => res.status == 'SUCCESS')
).subscribe(res => {
  // No need to check for status here 
  ..doStuffWithDataItems
});

If you require specific formatting of data from the backend, you can achieve that by applying map operator to transform the data accordingly before using it.

this.myService.reserveData(this.selectedData).pipe(
  mergeMap(res => {
    if (res.status == 'SUCCESS'){
      ...logSuccessMessagesAndOtherStuff
    }
    return this.myService.getReservedDataItemsForRequestId(this.requestId)
  }),
  filter(res => res.status == 'SUCCESS'),
  map(res => ({
    firstName: res.userdata.fname[0].toUpperCase() + res.userdata.fname.toLowerCase().slice(1),
    lastName: res.userdata.lname.toUpperCase(),
    age: (2020 - res.userdata.birthyear)
  }))
).subscribe(user => {
  ..doStuffWithUser
});

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

Evaluating a Observable epic that triggers another epic to run

I'm currently facing an issue with testing a Redux Observable epic that triggers another epic when dispatched. However, for some reason, the second epic is not being invoked. Let's take a look at how my epics are structured; const getJwtEpic = ...

Gather keyboard information continuously

Currently working with Angular 10 and attempting to capture window:keyup events over a specific period using RXJS. So far, I've been facing some challenges in achieving the desired outcome. Essentially, my goal is to input data and submit the request ...

It vanishes as soon as you move your cursor away during the animation

I created a button component with text animation, but I'm encountering an issue. When I hover over the button, the animation works smoothly. However, if I quickly move my cursor away or unhover in the middle of the animation, the text disappears unex ...

Unable to access npm run build on localhost

I have developed a web application using react and node.js, and now I want to test it with a production build. After running npm run build in the app directory, I successfully created a build folder. However, when trying to run the application using local ...

setting a variable with data retrieved from an AJAX call using jQuery

Here's a snippet of jquery code that I'm working with: var example = "example"; $.ajax({ url: root + "/servletPath", type: "GET", success: function (response) { alert(response); // displays the correct value example ...

The minimum and maximum limits of the Ionic datepicker do not function properly when selecting the month and day

Recently, I have been experimenting with the Ionic 2 datepicker. While the datepicker itself works perfectly fine, I've run into some issues when trying to set the min and max properties. <ion-datetime displayFormat="DD-MM-YYYY" [min]="event.date ...

The data source retrieved through the "get" API method is missing from the mat-table

Recently, I've started working with angularCLI and I'm facing an issue in creating a table where the dataSource is fetched from a fake API. Let me share my component class: import { Component, OnInit } from '@angular/core'; import { Fo ...

What strategies can be utilized to manage a sizable data set?

I'm currently tasked with downloading a large dataset from my company's database and analyzing it in Excel. To streamline this process, I am looking to automate it using ExcelOnline. I found a helpful guide at this link provided by Microsoft Powe ...

Steps to display a variable in JavaScript on an HTML textarea

I'm working on a JavaScript variable called 'signature' var signature; //(Data is here) document.write(signature) Within my HTML document, I have the following: <div id="siggen"> <textarea id="content" cols="80" rows="10">& ...

Limit the number of cards displayed per row using Angular Flexbox

I am currently working on a component that is supposed to display a maximum of x cards in each row, with the overflow (x+) scrolling in the horizontal direction. The challenge I am facing is getting exactly x cards to appear in one row, as shown in the ima ...

Issues with Ajax arise once URL re-routing is activated

When loading content using AJAX and ASP.NET web-methods, the following code is used to trigger the Ajax request: var pageIndex = 1; var pageCount; $(window).scroll(function () { if ($(window).scrollTop() == $(document).height() - $(window).height()) ...

Navigating through sections in NextJS-14: Utilizing useRef for seamless scrolling

In the past, I had developed an older portfolio website using Vite React + TS and implemented useRef for scrolling to sections from the Navbar. Now, my goal is to transition this portfolio to NextJS 14. I transferred my old components and style folders in ...

Tips for managing the number of items returned in a dataProvider using AS3

*Hey there! I'm looking to only display 100 items in a list component from a dataProvider, even if it contains more than 500 or even 1000 items. Specifically, I want the first 100 items with cameras on to be included, and then fill the rest to reach a ...

Is there a way to customize the color of specific sections on a dygraph chart?

I am looking to incorporate dygraphs into my website, but I need help with displaying a specific background color in certain parts of the chart. For example, I want the chart to show green during daylight hours. Can you assist me in achieving this? ...

Implementing a method to allocate rewards to individual players within a game Bank using arrays in Node.js and JavaScript

In my interactive game, players can choose between two sides to place their bets. At the end of the game, there will be one side declared as the winner and those who placed winning bets will receive a portion of what they wagered. However, I am facing an i ...

Issues encountered while trying to open and close a div using jQuery

.box-one { border: 0.1em solid #ccc; } .dropdown-info { display: none; } <div class="box-one"> <div class="header"> <h3 class="text-center">Sample Header</h3> </div> <div class="dropdown-info"> <p ...

Exploring the latest features of Angular 13 alongside a useful NPM module that utilizes

I have encountered an issue with my date-picker module for Angular that involves importing moment.js. The problem arises when I import the NPM package moment-es6, which imports moment.js in the following way: import * as moment from "moment"; ...

Generating unique triangle patterns through Webgl

Recently, I began learning webgl and have been attempting to create triangles with random sizes and positions similar to the image below using javascript. I understand that I need to utilize a for loop within the function initScene() but I'm uncertai ...

Mastering data extraction from JSON using React JS (with Axios)

Being new to ReactJS and axios, I am facing a challenge. I need to iterate through JSON data and extract values where the key is a number (e.g. 0, 1, 2...). However, I am unsure how to implement this in my code since the server provides dynamic JSON data ...

Is there a way for me to set distinct values for the input box using my color picker?

I have two different input boxes with unique ids and two different color picker palettes. My goal is to allow the user to select a color from each palette and have that color display in the corresponding input box. Currently, this functionality is partiall ...