Issue with Observable subscription not receiving notifications

I am currently working with an Observable to convert a promise into a subscription. This leads to a collection that requires iteration in order to call an HTTP Service on each element. I am using forkJoin to wait for all the calls to finish before proceeding, but unfortunately, my subscription is not triggering. Is there something crucial that I may be overlooking?

Observable.fromPromise(this.users.getElements()).subscribe(results => {
  Observable.forkJoin(
    results.map(
      aUser => this.HttpService.submitUser(aUser).subscribe(
        results => {
          this.progress += 1;
        },
        err => {
          this.progress += 1;
          this.handleError(<any>err);
        })
    ).subscribe(
      //the code never reaches these calls after completing all service calls
      data => {
        debugger;
        console.log(data);
        this.reset();
      },
      err => {
        debugger;
        console.log(err);
        this.reset();
      }
    ));
});

Answer №1

One important point is that you do not need to subscribe to each Observable individually when using the forkJoin() method. The operator handles this internally.

If you wish to receive a notification when each Observable completes, you can achieve this by using the

.do(undefined, undefined, () => {...})
callback.

let streams = [
  Observable.of(42).do(undefined, undefined, () => console.log('done')),
  Observable.of('a').delay(100).do(undefined, undefined, () => console.log('done')),
  Observable.of(true).do(undefined, undefined, () => console.log('done')),
];

Observable.forkJoin(streams)
  .subscribe(data => console.log(data));

The output in the console will be:

done
done
done
[ 42, 'a', true ]

Additionally, there is a .finally() operator available. Nevertheless, it functions differently from the .do() method.

UPDATE:

In case any of the source Observables encounter an error, the forkJoin() operator propagates that error (leading to failure).
Thus, individual errors from each source Observable should be handled separately (e.g., using the catch() operator).

let streams = [
  Observable.throw(new Error())
    .catch(() => Observable.of('error caught 1'))
    .do(undefined, undefined, () => console.log('done 1')),

  Observable.of('a')
    .delay(100).catch(() => Observable.of('error caught 2'))
    .do(undefined, undefined, () => console.log('done 2')),

  Observable.of(true)
    .catch(() => Observable.of('error caught 3'))
    .do(undefined, undefined, () => console.log('done 3')),
];

Observable.forkJoin(streams)
  .subscribe(data => console.log(data));

This will display the following results:

done 1
done 3
done 2
[ 'error caught 1', 'a', true ]

Answer №2

There might be no need to subscribe on the map in this scenario.

Observable.fromPromise(this.users.getElements()).subscribe(results => {
  Observable.forkJoin(
    results.map(
      aUser => this.HttpService.submitUser(aUser))
    ).subscribe(
      //The calls after all service calls are never reached
      data => {
        debugger;
        console.log(data);
        this.reset();
      },
      err => {
        debugger;
        console.log(err);
        this.reset();
      }
    ));
});

This rxjs example shows that they don't directly subscribe to individual observables - ForkJoin kicks them off, then waits for all of them to return (in your subscribe block).

Edit:

You can find the source code for forkjoin here:

https://github.com/Reactive-Extensions/RxJS/blob/master/src/core/linq/observable/forkjoin.js

It seems like there are no hooks available to track when each one finishes. Perhaps a better approach would be to individually subscribe to each mapped observable, increment the UI counting bar variable, and have a completion check to utilize the data effectively.

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

Developing a login feature in Angular 2 using Spring Security

I am currently in the process of integrating Spring Security with a custom Angular 2 login. Specifically, I have set up an endpoint in my application that is protected by Spring Security. If someone tries to access this endpoint, they will be redirected to ...

Tips for inputting transition properties in Material UI Popper

Currently, I am making use of material ui popper and I would like to extract the transition into a separate function as illustrated below: import React from 'react'; import { makeStyles, Theme, createStyles } from '@material-ui/core/styles& ...

The absence of the function crypto.createPrivateKey is causing issues in a next.js application

For my next.js application, I am utilizing the createPrivateKey function from the crypto module in node.js. However, I encountered an issue as discussed in this thread: TypeError: crypto.createPrivateKey is not a function. It seems that this function was a ...

TypeScript: a sequence of symbols representing a particular <type>

Perhaps I'm going crazy. I have a roster of potential nucleotides and a corresponding type: const DNA = ['G', 'C', 'T', 'A'] as const; type DNA = typeof DNA[number]; So, a DNA strand could be a sequence of an ...

Google Material Icons are failing to render in Angular application

The Google material icons are displaying correctly in Chrome within an Angular project, but are not rendering in Chrome's incognito mode or in Firefox. In the index.html file, the following lines are used to access the fonts library: <link href="h ...

Using Javascript or ES6, you can compare a nested array object with another array of elements and generate a new array based on

I am dealing with a complicated array structure as shown below sectionInfo = [{id: 1, name:'ma'}, {id: 2, name:'na'}, {id: 3, name:'ra'}, {id: 4, name:'ka'}, {id: 5, name:'pa'}]; abc = [{id:'1' ...

"TypeScript error: Arrays in interfaces are found to be undefined and not compatible

I'm struggling with correctly implementing the Typescript React Props syntax. In my project, I have an array of people, each of whom may have zero to many cars. There is a people container that holds all the people, each person has a car container tha ...

Using `it` with accessing class members

When testing whether a specific object/class is correctly wired up, I often utilize it.each to prevent writing repetitive tests. The issue arises when the type of the object doesn't have an index signature, requiring me to cast it to any for it to fun ...

Creating a new object in a Redux selector and returning it can be achieved by following these steps

Is there a way to create a new object in Redux selector and return it? I've been searching online, but haven't found an answer. For example: export interface UserModel { user: string, job: string, contact: string, sex: string // ...

Start up a server using Angular along with Node.js and Express framework

I am encountering an issue with configuring Express as a server in my Angular application. The app loads without any issues when accessing the HOME route, but when trying to access another route, I receive an error message: Cannot GET / This is how I hav ...

Unable to locate necessary assets, Electron encounters a resource deficiency

I'm currently developing a straightforward app using Angular and Electron. My goal is to set up the project as much from scratch as possible for the purpose of learning. Following this article, I have successfully created a basic Angular project that ...

The 'Subscription' type does not contain the properties _isScalar, source, operator, lift, and several others that are found in the 'Observable<any>' type

Looking to retrieve data from two APIs in Angular 8. I have created a resolver like this: export class AccessLevelResolve implements Resolve<any>{ constructor(private accessLevel: AccessLevelService) { } resolve(route: ActivatedRouteSnapshot, sta ...

Simplify an array in Javascript

I have a collection of objects structured in the following way: let list = [ { 'items': [ 'item 1', 'item 2' ] }, { 'items': [ 'item 3' ] } ] My goal is to flatte ...

Utilizing ES6, accessing the first element of an array of objects

How can I access the values of the first or a specific object in an array based on an index using ES6? arrayOne =[ { child: [ {e1: 'ABCD', e2: 'BCDF'}, {e1: '1234', e2: '5689'}, {e1: 'QAZ ...

Using React with TypeScript to implement a nested map function

I have developed an application using React typescript, incorporating redux and saga for state management. The data fetched is displayed on the browser with Google Maps integration where hovering over properties displays them on the map. To enhance user ...

Angular 4 Reactive Forms: How to Bind Data to Multiple Checkboxes

In Component: constructor(private prodService: productService, private fb: FormBuilder) { this.prodService.profile() .subscribe( result => { this.interested = result.category; //Retrieve all products this.ch ...

Managing animations with multiple components in Angular 2+

I am currently developing an Angular application that will utilize a series of Modals in a wizard-style setup. For this project, I am utilizing the Angular-cli tool. Below is the code snippet showing how I have set up my animations: animations:[ t ...

"Enhance your coding experience in VS Code with intelligent auto-completion for JavaScript files using type definitions that support import

Hey there! I've been experimenting with declaring custom types in d.ts files and using them in jsdoc annotations in JavaScript files to enable intellisense in VS Code. Let's take a look at an example: In the file types.d.ts import { Request } ...

typescript set x and y values to specific coordinates

Trying to map obstacles using a single object. Originally scattered randomly across the map, now I want to hard code X & Y coordinates with an array of numbers. However, TypeScript is only using the last value of the loop for the X coordinate. How can I a ...

Generate an array by filtering out null properties from a Javascript/Typescript object

I have a TypeScript plain old JavaScript object (POJO) structured as shown below: export interface Items { firstName?: String; lastName?: String; address?: String; phoneNumber?: number; city?: String; stat ...