The RxJS observable fails to initiate the subscribe function following the mergeMap operation

I am attempting to organize my dataset in my Angular application using the RxJS operators and split it into multiple streams. However, I am facing difficulties making this work properly. Inside my SignalRService, I have set up a SignalR trigger in the constructor to pass data from the server to the Subject that I created.

export class SignalRService {
  private connection?: signalR.HubConnection;
  private orders = new Subject<OrderModel[]>();
  orders$ = this.orders.asObservable();
    
  constructor() {
    // ... SignalR connection functions ...
    
    this.connection?.on('GetOrders', (data: OrderModel[]) => {
      this.orders.next(data);
    });
  }
};

In the OrderService, I subscribe to the orders$ Subject using pipe operators to split the data into three different streams based on the status of the Order object.

I apply map flattening, groupBy, and merging based on keys and corresponding data, but for some reason, this doesn't seem to be working and I'm unsure where to troubleshoot. When I insert tap operators between the current operators, only the first two taps are displayed. It seems like the third tap is never reached, hence failing to execute the subscribe operation. Additionally, when this.orders.next(data) is triggered more than once within SignalRService, nothing happens.

export class OrderService {
  // Observable sources
  private orderCategory0 = new BehaviorSubject<OrderModel[]>([]);
  private orderCategory1 = new BehaviorSubject<OrderModel[]>([]);
  private orderCategory2 = new BehaviorSubject<OrderModel[]>([]);
  private orders = [this.orderCategory0, this.orderCategory1, this.orderCategory2];
  // Observable streams
  orderCategory0$ = this.orderCategory0.asObservable();
  orderCategory1$ = this.orderCategory1.asObservable();
  orderCategory2$ = this.orderCategory2.asObservable();
  
  constructor(private signalRService: SignalRService) {
    signalRService.orders$
      .pipe(
        mergeMap((res) => res),
        //tap((res) => console.log(res)), <-- This one shows
        groupBy((order: OrderModel) => order.status),
        //tap((res) => console.log(res)), <-- This one shows
        mergeMap((group) => zip(of(group.key), group.pipe(toArray())))
        //tap((res) => console.log(res)), <-- This one doesn't
      )
      .subscribe(([groupId, data]) => this.orders[groupId].next(data));
  }
};

If I follow a similar approach as shown in the following code snippet inside OrderService, everything works as expected:

signalRService.orders$.subscribe((data: OrderModel[]) => {
  const groups = this.groupData(data);

  this.orderCategory0.next(groups[0]);
  this.orderCategory1.next(groups[1]);
  this.orderCategory2.next(groups[2]);
});

Currently, I am stuck and unsure if I am approaching this problem correctly. Any guidance or suggestions would be highly appreciated.

Edit: Furthermore, when I manually input Orders and use

of(orders).pipe(...).subscribe(...)
, bypassing the signalRService.order$ component, everything functions flawlessly.

Answer №1

One issue arises with the code snippet group.pipe(toArray()), as it will not emit due to group being an observable that remains open until order$ is completed, and toArray waits for the observable to complete before emitting. It seems like using groupBy may have been unnecessary in this scenario.

If I understand the example correctly, you are creating groups simply to pass them to the appropriate behavior subject based on a collection indexed by status. Instead of converting the array into an observable, you could use array.reduce (or Ramda's groupBy) to form groups without the need for streaming.

signalRService.orders$.subscribe((orders: OrderModel[]) => {
  const groups = orders.reduce((acc, cur) => {
      (acc[cur.status] || (acc[cur.status] = [])).push(cur);
      return acc;
    },
    {} as Record<string, OrderModel[]>);
  Object.values(entries).forEach(([k, v]) => this.orders[k].next(order);
});

If using groupBy is essential (possibly in a more complex scenario), then avoid using zip and opt for an inner pipe instead.

The subjects might also be unnecessary. You can map orders to the grouped object and project the individual groups as required.

const readonly orders$ = signalRService.orders$.pipe(
  map((orders) => orders.reduce((acc, cur) => {
      (acc[cur.status] || (acc[cur.status] = [])).push(cur);
      return acc;
    },
    {} as Record<string, OrderModel[]>)
  ),
  shareReplay(1)
);
const readonly orderCategory0$ = this.orders$.pipe(map(x => x['status0'] || []));
const readonly orderCategory1$ = this.orders$.pipe(map(x => x['status1'] || []));
const readonly orderCategory2$ = this.orders$.pipe(map(x => x['status2'] || []));

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

Troubleshooting: Issue with Button Layout in Ionic's ItemSliding Component

How can I create a list item that allows swiping to reveal an archive button? The requirement is for the icon to appear to the left of the text. I'm referring to the documentation on Button Layout: https://ionicframework.com/docs/api/components/item ...

Implementing a unit test in Angular for an HTTP interceptor that adds an XCSRF token to the header

My current task involves unit testing a global HTTP interceptor that retrieves the XCSRF token from a service call getResponse() and appends it to the header only in POST requests using the postResponse() method (as described below). I have attempted to t ...

Unable to retrieve a method from the model class in Angular 4

I attempted to utilize a method from the model class, but encountered an error: ERROR TypeError: act.sayHi is not a function Below is my code snippet: Model Class myModelClass.ts export interface IMymodel { name: string; addres ...

Error encountered during the build process in Angular microfrontends/multirepos using Webpack external module

I have developed an Angular project to integrate a microfrontend with another running Angular project. I have successfully imported the module into my application using webpack.config.js. Everything works fine on my local environment, but I encounter issue ...

Choosing a specific row in Angular 5

I'm completely new to Angular, so please bear with me :) I have a collection of user data that is presented in the following format: Below is my current HTML structure: EDIT - ADDED CRUD BUTTONS : <!--Add new button--> <button ty ...

unable to retrieve / interpret data from herdsmen using fetch

When sending a request to a node server, the server responds with headers and a blank body. Despite being able to view the headers in the network activity panel within dev-tools, I faced difficulties reading them using the following code: let uploaded ...

Using TypeScript generics to create reusable type definitions for reducers

I have a common reducer function that needs to be properly typed. Here's what I have come up with: export interface WithInvalidRows<T extends { [K in keyof T]: InvalidCell[] }> { invalidRows: T; } interface AddPayload<S extends WithInval ...

Mapping results into an array in Angular 2: A comprehensive guide

My current challenge involves converting an array with numerous columns into a more concise two-column array. Despite observing that the 'res' variable contains an array named 'result', I am encountering difficulty in successfully mappi ...

Using *ngFor alters the positioning of components

After implementing a flexbox container class to align my components horizontally, I noticed that when using input properties and a loop, they are displayed stacked vertically instead. <div class="flexbox-container" > <app-card></ ...

Utilizing Firebase 3 with Ionic 2 and cordova-plugin-camera for seamless file uploading

I have been attempting to upload images to Firebase storage using the cordova-plugin-camera but have not been successful: Below is the code I have been using: let options:any = { quality : 100, destinationType : Camera.DestinationType.DATA_URL, ...

Assign a predetermined value to a dropdown list within a FormGroup

I have received 2 sets of data from my API: { "content": [{ "id": 1, "roleName": "admin", }, { "id": 2, "roleName": "user", }, { "id": 3, "roleName": "other", } ], "last": true, "totalEleme ...

Utilizing type guards in prop functions for conditional rendering within React TypeScript adds an extra layer

In my code, I am conditionally rendering a Button. However, I encountered an issue on line 7 where TypeScript is indicating that the first parameter of the exportExcel function may be null even though it should not be, considering the conditional render lo ...

What causes the package-lock.json to contain newer versions of packages compared to package.json following a new npm installation in Angular?

Back in the year 2017 or around that time, npm reportedly made a decision to automatically update packages in package-lock.json if the versions listed in package.json were higher. An interesting issue I've noticed is that my project seems to be upgra ...

Toggle visibility of layers in ngx-mapboxgl

As I delve into ngx-mapboxgl, it becomes apparent that the documentation is lacking. My goal is to construct a layer with markers that can be toggled on and off. Despite following an example from the web, I encounter a runtime error claiming it cannot loca ...

Simultaneous requests and parallel execution

Within my NodeJS service, I have implemented a process to retrieve user details from a database and send them to another application via http. Processing each user record individually is slow, especially with millions of records. To address this issue, con ...

PDFJS integration in Ionic 2

Looking for guidance on integrating pdfjs into an ionic2 project. Any suggestions on how to import and use it would be greatly appreciated. Thank you! I'm familiar with using pdfjs, but I'm having trouble figuring out how to bring it into my ion ...

Ways to refresh Prism.js upon ngModel update in Angular 5

Currently, I am in the process of developing a CMS and facing an issue with re-rendering Prism.js to display syntax highlighting in the preview whenever there is a change in the body of the article. Below is the template code: <textarea [(ngModel ...

Visual Studio Code is encountering issues when trying to start a Node application

I am in the process of setting up a workflow for an express app using TypeScript, Visual Studio Code, and gulp. Here is the structure of my project: src/ <-- source files Start.ts Server.ts models/ Contact.ts Organization.ts bin/ <- ...

The absence of essential DOM types in a TypeScript project is causing issues

Recently, I've been working on setting up a web app in TypeScript but I seem to be missing some essential types that are required. Every time I compile using npm run build, it keeps throwing errors like: Error TS2304: Cannot find name 'HTMLEleme ...

Angular Validators.pattern() does not seem to function properly, despite yielding successful results in online regex testers

I have developed a regex pattern on Regex101.com and thoroughly tested it. However, when I applied it to my FormControl Validators.pattern method, it is exhibiting unexpected behavior. This regex pattern is meant for validating the Width input of a packag ...