Retrieving an Observable within an Observable is a feature found in Angular 9

Seeking a solution to return an Observable nested within another Observable. Although I've tried using the pipe and map operators, it doesn't appear to be functioning correctly for me. What could be causing the issue?

My development environment includes Angular 9.1.12 and rxjs ~6.5.4.

For instance:

Service1
import { Observable, of } from 'rxjs';

export class Service1 {

  test(): Observable<string> {
      console.log(1);
      return of('hey');
  }
}

Service2

import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export class Service2 {

  constructor(private service1: Service1) {}

  test(): Observable<string> {
    return this.service1.test().pipe(
      map((value: string) => {
        console.log(2);
        return value;
      })
    );
  }
}

Component

import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

export class Component implements OnInit {

  constructor(private service2: Service2) {}

  test(): Observable<void> {
    return this.service2.test().pipe(
      map((value: string) => {
        console.log(3);
      }));
    }
  }
}

Only "1" is displayed in the console.

Answer №1

It makes sense because you didn't subscribe to the observables, so they were never actually emitted or executed.

You need to subscribe in the component like this.

this.test().subscribe();

I have put together a stackblitz for you to experiment with.

PS: Remember to also unsubscribe when necessary. If these concepts are new to you, I recommend reading this article.

Answer №2

Similar to how functions only execute the code inside them when called upon, Observables run their code only when you subscribe.

When you call this.service1.test(), you will see an output of 1.

However, outputs 2 and 3 are not visible because you do not subscribe to those specific Observables.

export class Component implements OnInit {

  constructor(private service2: Service2) {}

  test(): void {
    this.service2.test().pipe(
      map(_ => console.log(3))
    ).subscribe();
  }
  
}

Answer №3

In the world of observables, there are two main categories: hot and cold. For the purpose of this discussion, we will focus on cold observables. Hot observables can be explored further here.

Cold observables, true to their name, wait to execute their internal logic until they have been subscribed to. This means that when you subscribe within a component, it triggers all the observables up to the innermost of('hey').

export class Component implements OnInit {
  constructor(private service2: Service2) {}

  ngOnInit() {
    this.test().subscribe();
  }

  test(): Observable<void> {
    return this.service2.test().pipe(
      tap((value: string) => console.log(value))
    );
  }
}

It's important to note that using the map operator in a component without a return statement will result in returning undefined. The map operator is typically used for transforming incoming values, while the tap operator is more suitable for side-effects like logging.

Unsubscribe

Additionally, subscriptions remain open unless an error occurs or they are explicitly completed. It's advisable to close these subscriptions once they are no longer needed.

For instance, in Angular, it's common practice to handle subscription closure in the ngOnDestroy hook to ensure they are closed when the component is destroyed.

export class Component implements OnInit, OnDestroy {
  sub: Subscription;

  constructor(private service2: Service2) {}

  ngOnInit() {
    this.sub = this.test().subscribe();
  }

  test(): Observable<void> {
    return this.service2.test().pipe(
      tap((value: string) => console.log(value))
    );
  }

  ngOnDestroy() {
    if (!!this.sub)
      this.sub.unsubscribe();
  }
}

There are various ways to gracefully handle closing open subscriptions. More details can be found here:

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

Building a search feature with a customized pipe in Angular

I attempted to create my own custom pipe in Angular 6 for filtering a list of campaigns using a search box. Strangely, I am having trouble getting the filter to work on the campaign list. Below is the code snippet that I have written. This is the implemen ...

Ensuring a Generic Type in Typescript is a Subset of JSON: Best Practices

I am interested in achieving the following: interface IJSON { [key: string]: string | number | boolean | IJSON | string[] | number[] | boolean[] | IJSON[]; } function iAcceptOnlyJSON<T subsetof IJSON>(json: T): T { return json; ...

Exploring the functionality of angular reactive forms in creating intricate JSON structures

After numerous attempts to resolve the issue on my own, I am reaching out to an Angular developer for assistance. My goal is to display a JSON object in the UI: Here is the JSON Object : items={"departure":"New York","arrival":"California","stations":[ ...

Cypress and Cucumber synergy: Experience automatic page reloads in Cypress with each test scenario in the Describe block

Hey, I'm facing an unusual issue. I have a dialog window with a data-cy attribute added to it. In my cucumber scenarios, I have one like this: Scenario: Users open dialog window When the user clicks on the open dialog button I've written Cypre ...

Launch a fresh window in Angular application without the need for a complete restart

How can I open a new window in Angular while passing values in the route to call an endpoint without causing the entire application to reload? It feels like such a hassle just to display a simple HTML page. Is there a better way to achieve this? ...

Leveraging Angular environment configurations for workspace libraries

I've been experimenting with Angular's latest version (>6) and am delving into the concept of using workspaces. One interesting feature is the ability to generate a library project with a simple CLI command: ng generate library api In my de ...

Best practices for organizing an array of objects in JavaScript

I have an array of objects with nested arrays inside, and I need to restructure it according to my API requirements. [{ containerId: 'c12', containerNumber: '4321dkjkfdj', goods: [{ w ...

Passing dynamic values to nested components within an ngFor loop in Angular

I'm currently facing an issue with a child component inside a ngFor loop where I need to pass dynamic values. Here is what I have attempted so far, but it doesn't seem to be working as expected <div *ngFor="let item of clientOtherDetails& ...

Activate the field once the input for the other field is completed

I have a form where the last name field is initially disabled. How can I make it so that the last name field becomes enabled only when the first name is inputted? <form> <label for="fname">First name:</label><br> ...

The @input field is failing to show the value entered by the user

I'm having trouble with my dynamic reactive form, as the value is not showing up <div *ngFor="let deliveryAcross of (deliveriesAcross | async)!; let i = index;"> <app-delivery-across [index]="i" [deliveryAcross]= ...

Can a function interface be implemented in TypeScript successfully?

I am interested in implementing this functionality: class MyFunc extends ((s: string) => boolean) { ... } This would allow an instance of MyFunc to act as a function that takes a string input and returns a boolean value, like so: const f = new MyFunc ...

LeafletJS tiles are only loaded once the map is being actively moved

Currently, I am facing an issue while trying to load a simple leaflet map in my Ionic 2 application. The problem is that not all tiles are loading correctly until the map is moved. this.map = new L.Map('mainmap', { zoomControl: false, ...

Steer clear of mentioning unbound methods, as they can lead to accidental scoping errors with 'this' when invoking static methods

I've been working on a method map based on a query from the Stack Overflow post linked here to assist me in dynamically calling a static method. But, I keep encountering this error message: Avoid referencing unbound methods that could lead to uninte ...

Best approach to inform pages about a variable update in Ionic

Imagine a scenario where we have a page called ListItemPage displaying a list of items: Within the ts file, there is a variable defined as items: any = []; In the html file, we find <ion-item *ngFor="let item of items"> Users can click on a (+ ...

Error in Typescript: The type 'string' cannot be assigned to the type '"allName" | `allName.${number}.nestedArray`' within the react hook form

Currently, I am tackling the react hook form with typescript and facing a challenge with my data structure which involves arrays within an array. To address this, I decided to implement the useFieldArray functionality. allName: [ { name: "us ...

When trying to click on the submit button in Angular forms, it fails to work

I'm encountering an issue with Angular forms when updating data. Despite the backend update method working fine, the submit button fails to trigger the data update. Can you help me spot the mistake in my code? Take a look at my Angular component HTML ...

Generate the Ionic build and save it to the /dist directory instead of the /www

Every time I execute the command ionic build, it generates a fresh /dist directory containing all the same files that are typically found in the /www directory. Despite my attempts to make updates to the /www folder, only the /dist folder gets updated. Wha ...

Authenticating users with Facebook using Ionic, Angular, Capacitor, and Firebase, as well as implementing role-based authentication

I successfully implemented Facebook authentication in my Android app using Ionic, Angular, Capacitor, and Firebase. The authentication is fully functional. What I attempted: Implementing role-based authentication. My solution: Storing the user's Face ...

"Import data from a text file and store it as an array of objects using Types

I need assistance with converting the information in my text file into an array of objects. Below is a snippet of the data from the text file: DOCNO NETAMOUNT IREF1 IREF2 DOCDT 001 30000 50 100 6/7/2020 2 40000 40 90 6/7/2020 Currently, t ...

Attempting to utilize a namespace-style import for calling or constructing purposes will result in a runtime failure

Using TypeScript 2.7.2 and VSCode version 1.21 with @types/express, I encountered an issue where in certain cases VSCode would report errors like: A namespace-style import cannot be called or constructed, and will cause a failure at runtime. Interestingly ...