Ways to achieve outcomes from functions employing concatMap within rxjs?

When calling two functions, I make use of fn1 and fn2. To execute them one after the other, I utilize concatMap.

I choose not to use exhaustMap and switchMap as they can result in nested "callback-hell".

  exhaustMap(() => 
     fn1().pipe(
       switchMap(() => fn2()))))

The main issue is how do I retrieve the results of fn1 and fn2 for the next function that follows the invocation of fn2?

Visit stackblitz.com for more.

import { of } from 'rxjs';
import { concatMap, tap } from 'rxjs/operators';

const fn1 = () => {
  console.log('Executing fn1');
  return of('fn1');
};

const fn2 = () => {
  console.log('Executing fn2');
  return of('fn2');
};

of(1)
  .pipe(
    concatMap(() => fn1()),
    concatMap(() => fn2()),
    tap({
      next: (result) => {
        console.log({ result }); /// <---- I want to access fn1 and fn2 here.
        console.log('Inside tap function!!!');
      },
      error: () => {
        console.log('Error inside tap function!!!');
      },
      complete: () => {
        console.log('Completed tap function');
      },
    })
  )
  
  .subscribe({
    next: (output) => {
      console.log({ output });
    },
    error: (error) => {
      console.log({ error });
    },
    complete: () => {
      console.log('Process Complete');
    },
  });

Answer №1

It seems there is no ready-made solution to escape the "operators-hell", but perhaps creating a custom operator could be the key?

Consider this approach:

import { from, ObservableInput, Observable } from "rxjs";
import { concatMap, map } from 'rxjs/operators';

const appendMap =
  <T, R extends ObservableInput<any>>(mapFn: (value: T) => R) =>
  (source$: Observable<T>) =>
    source$.pipe(
      concatMap((value) =>
        from(mapFn(value)).pipe(map((result) => [value, result] as const))
      )
    );

This custom operator can help you minimize the use of multiple operators and simplify your code:

import { of } from 'rxjs';
import { tap } from 'rxjs/operators';

const fn1 = () => of('fn1');

const fn2 = () => of('fn2');

of(1)
  .pipe(
    appendMap(() => fn1()),
    map(([_, fn1Result]) => fn1Result),
    appendMap(() => fn2()),
    tap({
      next: ([fn1Result, fn2Result]) => {
        console.log({ fn1Result, fn2Result });
        console.log('in tap!!!');
      },
      error: () => {
        console.log('in tap error!!!');
      },
      complete: () => {
        console.log('in tap complete');
      },
    })
  )
  .subscribe({
    next: (r) => {
      console.log({ r });
    },
    error: (e) => {
      console.log({ e });
    },
    complete: () => {
      console.log('complete');
    },
  });

Answer №2

One possible solution is to chain the second concatMap with the fn1() function and then use map to emit both values.

of(1)
  .pipe(
    concatMap(() => 
      fn1().pipe(
        concatMap((fn1Value) => fn2().pipe(
          map((fn2Value) => ({
            fn1: fn1Value,
            fn2: fn2Value
          }))
        ))
      )
    )

I have made adjustments to your code in this Stackblitz example.

Answer №3

If you're looking for a solution, check out this example on Stackblitz

const observable1$ = of(1);
const observable2$ = of(2);

observable1$.pipe(
    concatWith(observable2$)
  ).pipe(
      bufferCount(2)
).subscribe(console.log);

Answer №4

utilize the zip method:

view on stackblitz

import { of, zip } from 'rxjs';
import { concatMap, tap } from 'rxjs/operators';
console.clear();

const fn1$ = of('fn1');
const fn2$ = of('fn2');

zip(fn1$, fn2$)
  .pipe(
    tap({
      next: (a) => {
        console.log({ a }); // a === [fn1,fn2]
        console.log('in tap!!!');
      },
      error: () => {
        console.log('in tap error!!!');
      },
      complete: () => {
        console.log('in tap complete');
      },
    })
  )
  .subscribe({
    next: (r) => {
      console.log({ r });
    },
    error: (e) => {
      console.log({ e });
    },
    complete: () => {
      console.log('complete');
    },
  });

Answer №5

Here is a potential solution that could work:

from([1])
  .pipe(
    switchMap(() => fn1()),
    switchMap(resp_1 => fn2().pipe(
      map(resp_2 => ({resp_1, resp_2}))
    )),
    tap({
      next: ({resp_1, resp_2}) => {
        console.log(resp_1, resp_2); 
        console.log('inside tap function');
      },
      error: () => {
       console.log('tap function ran into an error!');
      },
      complete: () => {
       console.log('tap function completed successfully');
      },
    })
  )

This may seem complex due to the multiple operators used, but it should be manageable.

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

Refreshing Angular 4 route upon modification of path parameter

I have been struggling to make the subscribe function for the params observable work in my Angular project. While I have successfully implemented router.events, I can't seem to get the subscription for params observable working. Can anyone point out w ...

Next-Auth: Access Session in _app.js Directly Without Using getServerSideProps

When working with React.js and React-Auth, it's important to note that calling server-side functions such as getServerSideProps can prevent you from exporting your project using next export. Below is the content of my pages/_app.js, which I structured ...

Looking to handle a .csv file containing both quotes and commas within the quotes in Node.js - how can I achieve this

My code solution successfully parses a CSV file, but it doesn't handle cases where data has commas within quoted fields. For example, "not, accounted","normal". let filePath = Path.resolve(__dirname, `./MyData.csv`); let data = fs.readFileSyn ...

Using AJAX to load a PHP file in CodeIgniter is a great way to

I'm a beginner in the world of web development and I need help with loading my PHP file containing HTML content to update the span element. My framework of choice is CodeIgniter. Every time I try, I encounter an error. Below is my JavaScript code: ...

Having trouble receiving a complete response when making an ajax request to fetch an entire webpage

Currently, I am experimenting with J-Query Ajax functionality. My goal is to send a request in order to retrieve the entire HTML data of a page that I have hosted on bitbaysolutions.com. The issue arises when I load this URL and execute document.getElement ...

How can I ensure that my user responses are case-insensitive?

Currently, I'm facing a roadblock in my coding journey. I am trying to modify my code so that user responses are not case sensitive when compared for correctness. Can anyone offer some advice on how to achieve this? Check out the code snippet below: ...

Communication between AngularJS directives and controllers occur when a function is called upon a change

I have developed a unique custom directive which is defined as: <div class="col-md-6"> {{templateMapping[colProp].SheetPointer}} <select class="form-control" ng-model="selectedColumn" ng-change="changeMapping()" ng ...

Encountering a null value after making changes to the state in Reactjs

I'm currently working on a drag-and-drop web application using reactjs. The issue I'm encountering is that when I initiate the drag action, it triggers the handleDragStart function to update the state variable called selectedCard. However, when I ...

What is the best way to deploy a REST API utilizing an imported array of JavaScript objects?

I have been using the instructions from this helpful article to deploy a Node REST API on AWS, but I've encountered a problem. In my serverless.yml file, I have set up the configuration for the AWS REST API and DynamoDB table. plugins: - serverless ...

Using NextJS to navigate user journey by mapping an array of values from Formik to

I really appreciate all the help I've received so far, but I'm facing an issue trying to map an object with an array within it to the router. Here is my current code: const initialValues = { region: query.region || 'all', campt ...

Issue with Ng-Messages not functioning properly due to a custom ng-Include directive lacking a child scope

I have created a custom directive called lobInclude, which is similar to ngInclude but with no isolated scope: .directive("lobInclude", ["$templateRequest", "$compile", function($templateRequest, $compile) { return { restrict: "A", ...

Creating aliases for a getter/setter function within a JavaScript class

Is there a way to assign multiple names to the same getter/setter function within a JS class without duplicating the code? Currently, I can achieve this by defining separate functions like: class Example { static #privateVar = 0; static get name() ...

extracting the value of an option from a form control to utilize in the component's model

I'm currently facing an issue where I am unable to retrieve the value of an option selection in my component class for further processing. Despite setting the value as [value]="unit" in the view, it still shows up as undefined when passed through onMo ...

Transforming Thomas J Bradley's signature pad JSON into a PNG file using C# programming language

I have been experimenting with the Signature Pad plugin developed by Thomas J Bradley and successfully converted JSON signature to PNG using PHP. Now I am looking to achieve the same result using C#. There is a supplemental class called SignatureToImageDo ...

Quarterly Date Selection Tool with jQuery

I attempted to utilize the Quarter datepicker from: http://jsfiddle.net/4mwk0d5L/1/ Every time I execute the code, I encounter this problem: Cannot set property 'qtrs' of undefined. I copied exactly what was in the jsfiddle, and included the sam ...

Keep track of the toggled state and prevent any flickering when the page is reloaded, all without the

After extensive searching, I couldn't find exactly what I needed. Therefore, I decided to utilize cookies to remember the toggled state of a div whether it's hidden or visible. However, I encountered an issue where there is flicker happening as t ...

Creating a carousel with three thumbnails arranged in two rows

Currently, I am using a slider for my thumbnails. If you want to check out the code for this thumbnail slider, click on this link: thumbnails slider code My goal is to display 6 thumbnails in total, with 3 thumbnails shown in each row (2 rows total). Add ...

Is it necessary to separate Lodash orderby functions to ensure they function correctly?

For some reason, I'm having trouble sorting my data using lodash in my front-end client code. All the examples I've come across don't involve working with data in an interface, so I can't figure out where I'm going wrong. Let&apo ...

Using the onclick event with an image created through PHP code

I am currently in the process of developing a dynamic image represented as a graph displaying the number of documents generated each day. This interactive image is being created using PHP, and I aim to improve user engagement by enabling them to click on t ...

JavaScript can be used to extract a specific value from a SOAP response

In order to extract the Patient ID (PATAA000000040) from the SOAP response below using JavaScript and insert it into a Mirth destination, we need to target the value under the livingSubjectId tag. It's important to note that this tag may repeat, but w ...