Is there a simpler and more refined approach for handling Observables within RxJS pipelines?

Picture this: I have an observable that gives me chocolate cookies, but I only want to eat the ones without white chocolate. Since I am blind, I need to send them to a service to determine if they are white or not. However, I don't receive the answer immediately. Instead of waiting, I would prefer another observable.

Here is the code I ended up with, but I find it quite cumbersome and believe there must be a simpler and more elegant solution:

// Transform the observable
chocolateCookieObservable$.pipe(
  // Using switchMap to create a new stream that combines...
  switchMap((chocolateCookie: ChocolateCookie) => combineLatest(
    // An artificial stream with just one cookie...
    of(chocolateCookie),
    // And the answer from my cookie service (also an observable)
    this.chocolateCookieService
      .isChocolateCookieWithWhiteChocolate(chocolateCookie),
    // This results in an observable array containing both elements
  )),
  // Filtering the resulting observable array based on whether the cookie is white or not
  filter(([chocolateCookie, isWhite]: [ChocolateCookie, boolean]) => !isWhite),
  // Mapping the array to discard the boolean value, leaving only the filtered cookies
  map(([chocolateCookie]: [ChocolateCookie, boolean]) => chocolateCookie),
).subscribe((chocolateCookie: ChocolateCookie) => {
  this.eat(chocolateCookie);
}

Although this approach works reasonably well, it can become confusing when dealing with nested scenarios. Is there a direct way to filter or map the observable to obtain the required information without employing the combineLatest-of combination?

Answer №1

In order to improve the readability and maintainability of your code when working with complex async workflows using Observables, it is recommended to break down your statements into multiple parts.

By refactoring your code in this way, you can achieve a more organized structure that will make it easier to follow and debug. Here's an example of how your refactored code might look:

const isWhite$ = chocolateCookie$.pipe(
    switchMap((chocolateCookie: ChocolateCookie) => this.chocolateCookieService.isChocolateCookieWithWhiteChocolate(chocolateCookie)),
);

chocolateCookie$.pipe(
    withLatestFrom(isWhite$),
    filter(([chocolateCookie, isWhite]: [ChocolateCookie, boolean]) => !isWhite),
    map(([chocolateCookie]: [ChocolateCookie, boolean]) => chocolateCookie),
  ).subscribe((chocolateCookie: ChocolateCookie) => {
    this.eat(chocolateCookie);
  }

Additionally, it is worth mentioning that there is no need to explicitly label variables as 'Observable' if you are already using the $ syntax to indicate their Observable nature.

Answer №2

To exclude white cookies, you have the option to utilize the filter function within the switchMap operator. This will allow you to filter out any unwanted cookies before mapping the response from the service back to the cookie object.

Here's a brief illustration:

chocolateCookieObservable$.pipe(
  switchMap((chocolateCookie: ChocolateCookie) =>
    // asynchronously check for whiteness
    this.chocolateCookieService
      .isChocolateCookieWithWhiteChocolate(chocolateCookie)
      .pipe(
        // filter out white cookies
        filter(isWhite => !isWhite),
        // map back to the original cookie object
        mapTo(chocolateCookie)
      )
  )
).subscribe((chocolateCookie: ChocolateCookie) => {
  // Yum! Cookies!
  this.eat(chocolateCookie);
})

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

Adjust the color of the text in Ionic based on the condition

My current solution involves highlighting text in a small slider after a user tap, but it feels very makeshift. <ion-slide *ngFor="let loopValue of values"> <div *ngIf="viewValue == loopValue"> <b> {{loopValue}} </b> ...

Error: Unable to iterate through users due to a non-function error while attempting to retrieve the firestore document

I encountered an issue with my code, receiving the error message: TypeError: users.map is not a function. Can anyone help me identify what might be wrong? const [users, setUsers] = useState([]); const getData = async () => { try { const use ...

Tips for identifying and logging out a dormant user from the server side using Angular 2 Meteor

I'm currently diving into Angular 2 Meteor and working on a project that requires logging out the user when they close their browser window. I also need them to be redirected to the login page when they reopen the app. After searching online, I could ...

List the properties that the arguments object supports

During a NodeJS interview, I was presented with the following question: What properties are supported by the arguments object? a) caller b) callee c) length d) All Upon researching, I discovered that all 3 mentioned properties are supposed to be present ...

Which is better: Angular module for each page or component for each page?

We are getting started with Angular 8 and have a vision for a web application that includes: A navigation bar at the top with dropdown menu items leading to different UI pages. The main section will display each page, such as: - Sales section ...

What is the best way to choose the nearest element using the initial part of a class name?

I am working on a section of a table and need to hide a specific part when an icon is clicked. Below is the code snippet: <tr class="getmoreinfo_19"> <td>&nbsp;</td> <td colspan="3"> <div c ...

Apply a CSS class once a TypeScript function evaluates to true

Is it possible to automatically apply a specific CSS class to my Div based on the return value of a function? <div class="{{doubleClick === true ? 'cell-select' : 'cell-deselect'}}"></div> The doubleClick function will ret ...

Issue: template.config.js not found during creation of a React Native project on version 0.59.9

Every time I attempt to start a new react native project with version 0.59.9, an error pops up that says: Error: Couldn't find the "/var/folders/zc/h93bvpb573q24_5ynvgkn1wc0000gn/T/rncli-init-template-0YT6FZ/node_modules/react-native/template.config ...

Retrieve the ngModel's current value

One of the challenges I encountered is with a textarea and checkbox interaction. Specifically, once the checkbox is checked, I aim to have the value appear in the textarea. <div class="message-container"> <textarea *ngIf="mode === 1" ...

Using the timer function to extract data within a specific time frame - a step-by-step guide

Is there anything else I need to consider when the temperature increases by 1 degree? My plan is to extract data from my machine for the last 30 seconds and then send it to my database. set interval(function x(){ If(current_temp != prev_temp){ if((c ...

What is the reason behind prettier's insistence on prefixing my IIAFE with ";"?

I've encountered async functions in my useEffect hooks while working on a JavaScript project that I'm currently transitioning to TypeScript: (async ():Promise<void> => { const data = await fetchData() setData(data) })() Previously, ...

Is it possible to use async in the onChange handler of a React event?

Can async be used to pause execution until a function completes within an onChange event? Here is an example: const onChange = async (e) => { console.log(current[e.target.name]); await setCurrent({ ...current, [e.target.name]: e.targe ...

Image carousel with interactive buttons

I've taken over management of my company's website, which was initially created by someone else at a cost of $24,000. We recently made some edits to the slideshow feature on the site, adding buttons that allow users to navigate to corresponding p ...

The SourceMap in DevTools encountered a parsing error with the message: "chrome-extension

It's been about a week since I first noticed warning messages appearing in my Google Chrome console. https://i.sstatic.net/Aurgz.png Clearing the cache hasn't made a difference; the messages only vanish when in incognito mode. Any suggestio ...

Extending the declaration of JavaScript native methods is not possible when using TypeScript

When attempting to enhance the JS native String class by adding a new method, I encounter error TS2339. interface String { transl(): string; } String.prototype.transl = function() { // TS2339: Property 'transl' does not exist on type 'St ...

What is the best way to make this eerie javascript script communicate with my webpage or another jquery file?

I've been struggling with a javascript code that enables infinite scrolling in Tumblr. It seems outdated compared to jQuery, which I'm more familiar with. I've tried integrating this script with my jQuery functions and identifying DOM eleme ...

The values obtained from an HTTP GET request can vary between using Curl and Ionic2/Angular2

When I make a GET request using curl in the following manner: curl https://api.backand.com:443/1/objects/todos?AnonymousToken=my-token I receive the correct data as shown below: {"totalRows":2,"data":[{"__metadata":{"id& ...

Passing data to an Angular directive

I am facing an issue while trying to pass information through a view in a directive. Despite binding the scope, I keep seeing the string value 'site._id' instead of the actual value. Below is the code for the directive: angular.module('app ...

return to the previous mat tab by using the browser's back button

Currently working on an Angular project, I am faced with the challenge of configuring the Mat Tab to close the active tab and return to the previously accessed tab when the browser's back button is clicked. How can I accomplish this without relying on ...

Ways to adjust the color dynamics of a mat-slider

I am looking to dynamically change the color of a mat-slider. In my app, users have the ability to select any color from a color palette, and I want to display that selected color as the slider color. While I know you can add custom color names in the col ...