Tips for eliminating nested switchMaps with early returns

In my project, I have implemented 3 different endpoints that return upcoming, current, and past events. The requirement is to display only the event that is the farthest in the future without making unnecessary calls to all endpoints at once. To achieve this optimization, I devised a simple RxJs stream where I call the first endpoint, and if it doesn't return any data, I proceed to the next one. Here's how the code looks:

this.eventsService.getUpcoming(id).pipe(
      switchMap((upcoming) => {
        if (upcoming.length) {
          return of(upcoming);
        }
        return this.eventsService.getCurrent(id).pipe(
          switchMap((current) => {
            if (current.length) {
              return of(current);
            }
            return this.eventsService.getPast(id)
          })
        );
      }),
    // other transformation operators such as map, etc.

Is there a way to avoid nesting switch maps within each other?

Answer №1

In my opinion, one way to ensure sequential calls and automatically complete the chain when a useful response is received is by using concat(), take(1), and skipWhile():

concat(
  this.eventsService.getUpcoming(id),
  this.eventsService.getCurrent(id),
  this.eventsService.getPast(id)
).pipe(
  skipWhile(response => response.length === 0),
  defaultIfEmpty([]),
  take(1),
);

The take(1) operator will end the process once the condition in skipWhile is no longer met.

Answer №2

Consider trying out a different approach

this.service.getNext(id).pipe(
  switchMap((next) => {
    if (next.length) {
       return of(next);
    }
    return this.service.getCurrent(id)
  },
  switchMap((current) => {
     if (current.length) {
       return of(current);
     }
     return this.service.getPrevious(id)
  })
)

This technique avoids nesting the switchMap

Answer №3

Utilize the concat operator to establish an observable that sequentially delivers values from each individual observable. Connect this sequence to the find operator, which retrieves the first result meeting specific conditions and concludes the observable stream. This process effectively prevents subsequent observables from execution within the stream initiated by concat.

Distinguishing between 'first' and 'take'

An important aspect of the find operator is its ability to emit the last result if no matching conditions are met, making it a valuable feature for your scenario. This stands in contrast to using an operator like first, which throws an error if the source observable completes without finding a match, or take, which remains mute since prior operators have already filtered emissions.

In your specific case, even if all responses return empty, you will still receive an empty array as output.

concat(
  // Perform requests in sequence.
  this.eventsService.getUpcoming(id),
  this.eventsService.getCurrent(id),
  this.eventsService.getPast(id)
).pipe(
  // Deliver the first result that fulfills the set condition.
  find(response => response.length > 0) 
);

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

how to send both the useState setter and object as props to a child component in React using TypeScript

Having an issue with passing useState setter and object (both together) to the child component. Successfully passed the object by spreading it like this {...object}, but unsure of the syntax to pass the setter along as well. Here's a code example: < ...

The execution of jQuery was hindered due to the implementation of PHP include

Having an issue with jQuery not working in index.php when including the file header.php. The nav sidebar is included, but clicking the chevron does not trigger anything. It only works when I directly include header_user.php without checking the UserType in ...

Facing an issue with the ng2-carousel component where the left and right arrow icons are

Currently employing ng2-carouselamos Visit the ng2-carouselamos npm page here After duplicating the provided HTML template, I have encountered issues with clickable events not functioning properly. The absence of a TypeScript file in the documentation ma ...

Determine the type of embedded function by analyzing the callback

Are you struggling to create a function that takes an object and returns a nested function, which in turn accepts a callback and should return the same type of function? It seems like achieving this with the same type as the callback is posing quite a chal ...

Retrieve the property value from a nested object using a key that contains spaces

Presenting my object: let obj = { innerObj: { "Key with spaces": "Value you seek" } } Upon receiving, I am unaware of the content within obj. I possess a string variable holding the key to access the value. It appears as follows: let ke ...

Combining inheritance and isolated scopes: a comprehensive guide

I've encountered a situation where I need to sort an HTML table. Here is the code snippet: <table> <thead> <tr> <th custom-sort-one order="'Name'" >Name</th> </ ...

The system couldn't locate the module: Issue: Unable to find module 'fs' within the directory

I am currently working on integrating the ADAL JS sample code from this link into a SharePoint framework client web part. My code is fairly straightforward, as I have already installed packages like adal, fs, and node-fs using NPM. However, when running t ...

Troubleshooting drag-and-drop functionality in a JavaScript HTML5 application resembling a Gmail upload interface

Here is a snapshot of my user interface: Each node in the tree structure is represented by an <li> element along with an <a> link. Furthermore, each folder serves as a dropzone for file uploads similar to the drag-and-drop feature found in Gm ...

Ajax updates to an element are not reflected until the for loop has completed

I am looking for a way to print a series of numbers sequentially using AJAX. Here is an example of what I want to achieve: (each new line represents an update of the previous line!) Output is: 1 12 123 1234 12345 123456 ... I ...

Embrace the flexibility of using Next.js with or without Express.js

Recently, I started the process of migrating a project from create-react-app to next.js. However, I am facing uncertainty when it comes to migrating the backend of the project. Currently, my backend is built with an express server. In next.js, there are p ...

Having trouble deploying an Angular Universal app to an AWS S3 bucket with server-side rendering (SSR

Transitioning from an Angular9 application to make it SEO friendly required me to switch to Angular Universal SSR. I followed the steps below: Ran the command: ng add @nguniversal/express-engine Ran the command: npm run dev:ssr Ran the command: npm run bu ...

Customizing the renderInput of the Material UI DatePicker

Recently I integrated material-ui into my React project with TypeScript. I implemented the following code based on the example provided on the official website. import AdapterDateFns from '@mui/lab/AdapterDateFns'; import DatePicker from '@m ...

The shared hosting environment encountered an error during the Next JS build process

When I execute the command "npm run build" on my shared hosting server, it throws an error message: spawn ENOMEM. Interestingly, this command runs perfectly fine on my localhost and has been running smoothly on the hosting server for a few weeks until yest ...

Navigate to the homepage section using a smooth jQuery animation

I am looking to implement a scrolling feature on the homepage section using jquery. The challenge is that I want the scrolling to work regardless of the page I am currently on. Here is the HTML code snippet: <ul> <li class="nav-item active"> ...

Navigating Google GeoChart Tooltips using Google Spreadsheet Data

My objective is to create a custom GeoChart for the company's website that will display data specific to each state in the US region based on team member assignments. The GeoChart should color states according to which team member helps that state&apo ...

A step-by-step guide on integrating a Django template tag and HTML element into an HTML page using Javascript

Is there a safe way to insert HTML that includes Django template tags using JavaScript in my project? For instance, if my template contains the following code: <div id="some-element"> <span id="my-tag">{{ my_data }}</sp ...

Is there a way to retrieve a different value within the JavaScript code (imagepicker)?

I need help with setting up a page where users can choose an image to forward them to another page. However, I'm facing an issue when the user chooses two images at once. Can anyone provide ideas on how to handle forwarding in this scenario? You can c ...

Using ngFor to Filter Tables in Angular 5

Are you in the midst of implementing multiple data filters in an Angular Application that displays data using a Table and ngFor? You may have explored different methods such as using Pipe in Type Script, but discovered that it is not recommended accordin ...

What is the best way to execute a function while utilizing its default options?

I am working on a project that involves a drop down box and an input box. Here is the HTML code for the drop-down box: <select #select id="id" class="class" (change)="onChange($event)"> <option value="1"> 1 </option> <option v ...

The timeline shows the movement of the jQuery object

I currently have a timeline bar that looks like this: <div class="plan-bar main-gradient"></div> https://i.stack.imgur.com/ybJar.jpg My question is, how can I make the red box move in real-time along this timeline bar? Thank you for your hel ...