Could anybody provide an explanation on how my RXJS code functions?

 this.httpService.get('/user/appUser').pipe(
  concatMap(users => users),
  concatMap(user =>
    forkJoin({
      billingAddr: this.httpService
        .get('/user/appUserAddr', new HttpParams()
          .set('where', JSON.stringify([{ pk_addr_name: user['fk_billing_addr_name'] }]))
        ),
      shippingAddr: this.httpService
        .get('/user/appUserAddr', new HttpParams()
          .set('where', JSON.stringify([{ pk_addr_name: user['fk_shipping_addr_name'] }]))
        )
    }).pipe(map(addr => {
      user['billingAddr'] = addr.billingAddr;
      user['shippingAddr'] = addr.shippingAddr;
      return user;
    }))
  ),
  tap(res => console.log(res)),
  toArray()
);

The initial HTTP Request to get '/user/appUser' will retrieve an array similar to the following:

[  
{user_name:'test1',fk_billing_addr_name:'addr1-1',fk_shipping_addr_name:'addr1-2'},  
{user_name:'test2',fk_billing_addr_name:'addr2-1',fk_shipping_addr_name:'addr2-2'}
]

Next, I will fetch the separate billingAddr and shippingAddr values and append them back to the corresponding user object. This is handled in the second part of the code within the concatMap function.

After processing, the final output will appear as shown below:

[  
{user_name:'test1',fk_billing_addr_name:'addr1-1',fk_shipping_addr_name:'addr1-2',billingAddr:[...],shippingAddr:[...]},  
{user_name:'test2',fk_billing_addr_name:'addr2-1',fk_shipping_addr_name:'addr2-2',billingAddr:[...],shippingAddr:[...]}
]  

Although the current implementation works effectively, there seems to be redundancy in the first concatMap(users=>users) operation. Is it possible to simplify the code by utilizing just one concatMap? Are there any other areas that can be optimized?

Answer №1

This question sparks curiosity. Let's dive into what's unfolding.

  1. Start with the initial array.
  2. The first concatMap sequentially emits each element of the array, similar to from(array).
  3. Map to observable from forkJoin using the second concatMap.
  4. Modify each element by fetching and assigning two new properties to it using forkJoin.
  5. Merge all elements/emissions back together at the end as an array using the toArray() operator and emit.

Overall, everything seems fine, except for the dependency on the current user to fetch its data before moving on to the next.

If you want to fully parallelize the fetches, consider using two forkJoins. The inner forkJoin works similarly to the current setup, while the outer one replaces the need for concatMap and toArray. You can replace switchMap with any other mapping operator since Angular HTTP requests complete after the first emission, making the choice of operator impact-free.

Note: This code has not been tested. Kindly let us know if you encounter any unintended outcomes.

this.httpService.get('/user/appUser').pipe(
  switchMap(users => 
    forkJoin(users.map(user => 
      forkJoin({
        billingAddr: this.httpService
          .get('/user/appUserAddr', new HttpParams()
            .set('where', JSON.stringify([{ pk_addr_name: user['fk_billing_addr_name'] }]))
          ),
        shippingAddr: this.httpService
          .get('/user/appUserAddr', new HttpParams()
            .set('where', JSON.stringify([{ pk_addr_name: user['fk_shipping_addr_name'] }]))
          )
      }).pipe(
        map(addr => ({
          ...user,
          billingAddr: addr.billingAddr,
          shippingAddr: addr.shippingAddr
        }))
      )
    ))
  )
)

You could achieve a similar outcome in your code by swapping out concatMap with mergeMap

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

What is the best way to utilize scope apply or run functions upon successful completion in Angular 8 jQuery ajax requests?

Due to reasons that I won't delve into here, I have opted to use jQuery ajax instead of Angular's http. This means I am making an ajax call to my php server. However, a problem arises where any code within the success/error blocks is confined to ...

conducting thorough analysis for detecting modifications akin to $watchCollection in Angular2

I have a situation where I am passing an array of objects from my parent component to child components. Even when a new item is added to the array or the property of an existing object changes, it fails to trigger the ngOnChanges for the affected component ...

Leverage the JSON Web Token module within a Chrome extension

Currently in the process of developing a chrome extension but encountering an issue with loading the json web token node module in my Node.js setup. background-script.ts import jwt from 'jsonwebtoken'; // import * as jwt from '../node_mod ...

Using TypeScript with React: Initializing State in the Constructor

Within my TypeScript React App, I have a long form that needs to dynamically hide/show or enable/disable elements based on the value of the status. export interface IState { Status: string; DisableBasicForm: boolean; DisableFeedbackCtrl: boolean; ...

choose a distinct value for every record in the table

My goal is to only change the admin status for the selected row, as shown in the images and code snippets below. When selecting 'in-progress' for the first row, I want it to update only that row's status without affecting the others. <td ...

What's the best way in Angular 6 to set focus on an element that's being made content editable?

I am currently utilizing the contentEditable attribute in Angular 6 to allow for editing the content of elements within an ngFor loop. Is there a way to focus on a tag element when its contentEditable attribute is set to true? <div class="tag" *ngFor= ...

Utilize Angular's ability to set values in line while clicking using an asynchronous function

I am facing a unique challenge where I need to assign a value to a variable inline using a click event that triggers an async function call. The scenario involves rendering a deeply nested and complex set of objects on the screen within an ng-template (e.g ...

Can I inform the interpreter that my function in TypeScript specifically handles undefined and null values?

Consider a scenario where there is a method isEmpty that verifies if a value is empty, null, or undefined, and returns true accordingly. In TypeScript, this method may not effectively communicate to the interpreter, leading to a red underline in IDEs like ...

Angular Form Template Unidirectional Data Binding Example

I'm facing a challenge with one-way binding to a default value in my HTML form. Within my component, I have a Connection string that is initially set from local storage: export class AuthAdminComponent implements OnInit { public authenticated = f ...

Issue with ng2-img-cropper in Angular 2: Unable to crop images from a URL

I need help with ng2-img-cropper for cropping a photo (not an avatar). You can find the library here: https://github.com/cstefanache/angular2-img-cropper I tried following this example: https://embed.plnkr.co/V91mKCNkBQZB5QO2MUP4/ It seems that the libra ...

The assigned type 'string' for Apache ECharts does not match the expected type 'pictorialBar'

This demonstration is functional. Nevertheless, the options utilize any and my goal is to convert them to the EChartOption type. This is my current progress and the demonstration compiles successfully with this setup (With type: 'bar' commented ...

Storing my token in the cookie using setCookie is proving to be difficult for me

While trying to authenticate my site with nextAuth and nookies, I am facing an issue where the token is not getting stored in the cookie. The API sends back a token and a refresh, and even though storing the refresh works fine, the token just doesn't ...

Accessing several values in Angular by clicking

I have a dropdown that contains an input field and two more dropdowns. I am looking for a way to retrieve the values of all three fields when the search button is clicked. Screenshot https://i.sstatic.net/5Imaq.png Code HTML <nz-dropdown-menu #menu=&q ...

Error in Angular 10/ Typescript: Cannot find property in type 'Object'.ts

Transitioning from Angular 1 to Angular 10 has led me to dive into learning typescript. Please bear with me if there are any errors as I navigate this new territory. While I have a substantial amount of code, here is the main issue at hand. In Angular 1, I ...

Alter the class based on the incoming string from the rxjs stream

I have a stream that outputs strings, and based on these strings I want to apply certain classes to a specific tag: If the string is "ok", add class "fa-check" If the string is "loading", add classes "fa-spin" and "fa-spinner" If the string is "error", a ...

In the hook of Vue 3, the return type object within `this` is consistently evaluated as `undefined`

Could someone explain why, in the provided code snippet, the this inside the return block remains undefined? export const useAutoSave = ( cacheKey: string, interval: number, getSaveData: () => Omit<SaveDto, 'savedTime'>, ) => { ...

On a mobile device, the keyboard is hiding the PrimeNG dropdown

While my dropdown works flawlessly on a desktop browser, I encountered an issue when accessing it on an Android device. The dropdown immediately disappears and the virtual keyboard pops up, which is not the case on iOS devices. I suspect that the problem ...

Angular 2 - Component's Off-click Feature Falters

Achieving a desired effect using Angular 2, I have implemented a component with a small popup <div>. The popup is dismissed when the user clicks anywhere on the document except for the popup itself. To achieve this functionality, I utilize HostListen ...

Asynchronous task within an if statement

After pressing a button, it triggers the check function, which then executes the isReady() function to perform operations and determine its truth value. During the evaluation process, the isReady() method may actually return false, yet display "Success" i ...

The attribute 'finally' is not found on the data type 'Promise<void>'

I've been attempting to implement the finally method on a promise but continue running into this issue. Property 'finally' does not exist on type 'Promise<void>'. After researching similar problems, I found suggestions to a ...