Guide on Combine Multiple Observables/Subscriptions into a Nest

1. A Puzzle to Solve

I am faced with the challenge of implementing a dynamic language change flow for my blog. Here is an overview of how I envision it:

  1. The user initiates a language change by clicking a button that triggers an event (Subject).
  2. This event is then used to query Firebase in order to fetch the appropriate page content based on the selected language.

If I handle each step independently, there might be an issue where the query does not get triggered when the user changes the language midway. This makes me think that a nested subscription/observable approach might be necessary. Am I on the right track?

2. Current State of My Code

In my attempts so far, nesting subscriptions did not yield the desired outcome. I suspect it could be due to scoping issues. Currently, this is the code snippet I am experimenting with:

this.headerService.langChanged.pipe(
  map(
    (newLang: string) => {
      this.db
        .collection<AboutMePage>(
          this.aboutMeCollectionName, 
          ref => ref.where('lang', '==', newLang)
        )
        .valueChanges();
  })
)
  .subscribe(
    value => {
      this.aboutMe = value[0]
    }
  );

The headerService.langChanged is an instance of Subject<string>.

Is there an operator in rxjs specially suited for this scenario? concat seemed promising, but it waits for the previous Observable to complete, which is not ideal in this context. Additionally, passing parameters to the next observable adds another layer of complexity...

Answer №1

Utilizing functions like concat, switchMap, merge, or forkJoin can provide you with suitable solutions based on your specific requirements, such as concurrency. For instance, I have created a Stackblitz demo using forkJoin which you can check out here: https://stackblitz.com/edit/angular-xyf8a6

By examining the console logs in the example, you can observe the varied durations of each inner

Observable</code and understand how <code>forkJoin
ensures that the overall process is completed in the time taken by the slowest observable.

The subscription setup in the demonstration is as follows:

this.langChanged
  .subscribe(newLang => {
    console.log(`language changed ${newLang}`);
    this.cancelLangChange.next();
    forkJoin(
      this.getUserName(newLang), 
      this.getUserBio(newLang), 
      this.getUserCreationDate(newLang)
    )
      .pipe(takeUntil(this.cancelLangChange))
      .subscribe(([username, bio, userCreationDate]) => {
        this.aboutMe.username = username;
        this.aboutMe.bio = bio;
        this.aboutMe.userCreationDate = userCreationDate;
      });
  });

To handle instances where a user switches languages while the initial change is still loading, I introduced a second Subject named cancelLangChange. This subject is designed to terminate the forkJoin subscriptions if such situations arise.

Answer №2

After some tinkering, I found a solution using the pipe and map functions. By utilizing the map operation, we can create a new observable based on the parameters of the initial one. This nested subscription approach ultimately allows us to retrieve the desired data.

this.aboutMeSubscription = this.headerService.langChanged.pipe(
  map(
    (newLang: string) => {
      return this.db
        .collection<AboutMePage>(
          this.aboutMeCollectionName, 
          ref => ref.where('lang', '==', newLang)
        )
        .valueChanges();
  })
)
  .subscribe(
    langChangedAboutMeObs => {
      this.langChangedSubscription = langChangedAboutMeObs
        .subscribe(
          (value: AboutMePage[]) => {
            this.aboutMe = value[0];
          }
        );
    }
  );

To improve functionality, I updated my Subject to a BehaviorSubject, ensuring an initial value is emitted preemptively. Additionally, it's crucial to unsubscribe from both subscriptions in the ngOnDestroy lifecycle hook.

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

Having trouble implementing ng2-charts in Angular 4 when using shared components

Using angular 4.0.0, angular-cli 1.2.1, and ng2-charts 1.6.0 has been a smooth experience for me so far. However, I encountered an issue when trying to incorporate ng2-charts into "shared" components. In my setup, I have a shared-components.module that is ...

Having trouble deserializing the POJO that was sent from an Angular HTTP post request within my Spring Boot POST-mapped function

My application is a coffee shop, and I am trying to send an array of items to my Spring Boot backend. However, Jackson is throwing an exception: Cannot construct instance of `me.andrewq.coffeeshop.menu_items.Menu` (no Creators, like default constructor, e ...

The functioning of the Angular4 website is currently experiencing issues

Recently, I made the switch from Angular2 to Angular4 on my website. When running 'ng serve', everything works perfectly fine except for a warning about a deprecated template that should be changed to 'ng-template'. I use ng-bootstrap a ...

A guide to accessing parent attributes in Vue3 using typescript

Within my child component, I am facing an issue where I need to access the parent object but the commented lines are not functioning as expected. The structure of AccordionState is defined below: export type AccordionKeys = | "open" | "disa ...

Simplify TypeScript code by converting null or undefined values to numbers

When working with a product, it's important to keep in mind that it can be undefined or null; furthermore, the price within the product can also be undefined or null. For example: getClasses(key: number): string { let product = this.mo ...

Upgrade from Next.js version 12

Greetings to all! I have recently been assigned the task of migrating a project from next.js version 12 to the latest version. The changes in page routing and app routing are posing some challenges for me as I attempt to migrate the entire website. Is ther ...

Utilizing typed arrays within generic functions

Within a library, there exists a helper function designed to work with arrays of any type. The next step is to expand its functionality to also accommodate typed arrays. However, the challenge lies in the absence of a common base class for typed arrays or ...

Utilizing string literals as index signatures

I've created a code snippet called MyTest that maps over an object: type MyTest<T> = { [P in keyof T]: T[P]; }; type Result = MyTest<{hello: 'world', foo: 2}>; // ^? type Result = { hello: 'world', foo: 2 } ...

Leverage the power of forkJoin in JavaScript by utilizing objects or sourcesObject

I'm currently facing an issue with my code snippet below: getInformations().subscribe( informations => { let subs = []; for (const information of informations) { subs.push(getOtherDetails(information.id)); } ...

The FormGroup instance does not return any input method when using the get input function

I am facing an issue where a custom error message should only display if the input for foo is invalid. However, it seems like the line of code myForm.get('foo') is returning null. Below is the simplified version of component.html: <form [for ...

An empty page persistently remains blank due to routing issues in Angular

Whenever I click on the "Portfolio" link, https://i.sstatic.net/RTxkC.png The Portfolio page doesn't appear as expected (shown below) https://i.sstatic.net/wJBP8.png I'm having trouble understanding the routing system. Below is the structure ...

Is there a way to adjust this angular2 service to make it slightly more synchronous?

My goal is to create an Angular2 service that performs the following tasks: FTP to a remote server Read certain lines from a file Create a 'results' JSON object and return it to the component that called the service I have successfully impleme ...

Angular 6 provides a regular expression that specifically targets the removal of any characters that are not numbers and enforces the allowance of

I have tried various solutions to restrict input in an Angular material input box, but none seem to be effective for my specific case. I need the input field to only allow numbers and a decimal point. Any other characters should be automatically removed as ...

Error occurs on Chrome while Angular 7 HTTP POST works fine on Edge and Firefox

My application is experiencing a strange issue where the HTTP POST method works fine on Firefox and Edge browsers, but not on Chrome. The application is built using Angular 7 and .NET Core 2.2. It has a CRUD example that functions correctly in all browser ...

Creating a Modal using Typescript with NextJS

Currently, I'm working on creating a modal within my app using NextJS with Typescript. Unfortunately, I've been struggling to eliminate the warning associated with my modal selector. Can someone provide guidance on how to properly type this? cons ...

Encountering the error message "Receiving 'Multiple CORS header 'Access-Control-Allow-Origin' not allowed' while accessing my Laravel API from Angular"

After successfully developing an API with Laravel that functioned perfectly with Postman, I am now working on its front-end using Angular. However, I keep encountering this error every time I send a request to the API: Cross-Origin Request Blocked: The Sa ...

Error: Angular SSR does not recognize IDBIndex

Attempting to build my Angular application using the command npm run build:ssr. The application built successfully, but when running the command npm run serve:ssr, I encounter the following error: ReferenceError: IDBIndex is not defined Note: Upon invest ...

The most efficient method for distributing code between TypeScript, nodejs, and JavaScript

I am looking to create a mono repository that includes the following elements: shared: a collection of TypeScript classes that are universally applicable WebClient: a react web application in JavaScript (which requires utilizing code from the shared folde ...

Having trouble with Angular NgbModal beforeDismiss feature?

My goal is to add a class to the pop up modal before closing it, and then have it wait for a brief period before actually closing. I've been trying to do this using the beforeDismiss feature in the NgbModalOptions options in Angular Bootstrap's d ...

Utilizing child component HTTP responses within a parent component in Angular: a comprehensive guide

As a newcomer to Angular, I find myself struggling with http requests in my application. The issue arises when I have component A responsible for retrieving a list of IDs that need to be accessed by multiple other components. In component B, I attempted t ...