Angular 12: Ensure completion of all data fetching operations (using forkJoin) prior to proceeding

Within my ngOnInit function, I am looking for a way to ensure that all requests made by fetchLists are completed before moving forward:

  ngOnInit(): void {
    this.fetchLists();

    this.route.params.subscribe(params => {
         this.doSomethingWithFetchedLists();
      }
    });
  }

  fetchLists(): void {
    this.httpHandlerCached.getListsA()
      .subscribe(listA => this.listA = listA);
    this.httpHandlerCached.getListsB()
      .subscribe(listB => this.listB = listB);
    this.httpHandlerCached.getListsC()
      .subscribe(listC => this.listC = listC);
  }

I would like to highlight that my previous inquiry was advised to use "forkJoin": Wait for multiple promises to finish

However, even after implementing forkJoin, I am facing the same issue:

  fetchListnames() {
    return forkJoin([
      this.httpHandlerCached.getListsA(),
      this.httpHandlerCached.getListsB(),
      this.httpHandlerCached.getListsC(),
    ]).subscribe(res => {
        this.listA = res[0];
        this.listB = res[1];
        this.listC = res[2];
      });
  }

Given the suggestion to use forkJoin, how can I ensure that the forkJoin operation is complete before proceeding (i.e., before calling

this.doSomethingWithFetchedLists()
)?

Answer №1

It is not advisable to nest subscriptions as recommended by another response. Instead, it is better practice to utilize rxjs pipes and subscribe just once.

In this scenario, one might assume that placing this.route.params inside the forkJoin would work, but since this.route.params never completes, forkJoin will not emit (as per its implementation). To ensure that this.route.params completes, you can use take(1) within a pipe, resulting in the following code:

forkJoin([
      this.httpHandlerCached.getListsA(),
      this.httpHandlerCached.getListsB(),
      this.httpHandlerCached.getListsC(),
      this.route.params.pipe(take(1))
    ]).subscribe(res => {
        this.listA = res[0];
        this.listB = res[1];
        this.listC = res[2];
        this.doSomethingWithFetchedLists();
      });

Another alternative is to use combineLatest instead of forkJoin, which emits whenever any observable changes (waiting for all observables to emit at least once initially).

combineLatest([
          this.httpHandlerCached.getListsA(),
          this.httpHandlerCached.getListsB(),
          this.httpHandlerCached.getListsC(),
          this.route.params
        ]).subscribe(res => {
            this.listA = res[0];
            this.listB = res[1];
            this.listC = res[2];
            this.doSomethingWithFetchedLists();
          });

If opting for the latter method, remember to manually unsubscribe (or use take(1) in a pipe) to prevent memory leaks.

Answer №2

Expanding on Christian's explanation, the withLatestFrom method can be utilized to eliminate nested subscriptions.

fetchData() {
    return forkJoin([
        this.httpHandlerCached.getDataA(),
        this.httpHandlerCached.getDataB(),
        this.httpHandlerCached.getDataC(),
    ])
    .pipe(
        withLatestFrom(this.route.params.pipe(take1)),
        map(([result, parameters]) => {
            return { result, parameters }
        })
    )
    .subscribe(response => {
        let result = response.result;
        let parameters = response.parameters;
        this.dataA = result[0];
        this.dataB = result[1];
        this.dataC = result[2];
        this.processFetchedData();
    });
}

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

I suggest installing the ng2-search-filter package for easy search functionality

Is there a recommended alternative to ng2-search-filter? I encountered an error with this one: 'Ng2SearchPipeModule' does not appear to be an NgModule class.(-996002). The error message in ng2-filter.module.d.ts(1, 22) suggests that the library ( ...

What is the correct way to declare the mongoose _id in a TypeScript interface?

I have a question about utilizing Mongoose and TypeScript using the interface+class+schema approach. When it comes to storing the _id field, what is the best method? I understand that the database stores it as a bson ObjectID. However, I've come acr ...

Error message indicating that the function is not defined within a custom class method

I successfully transformed an array of type A into an object with instances of the Person class. However, I'm facing an issue where I can't invoke methods of the Person class using the transformed array. Despite all console.log checks showing tha ...

Place a hook following the storage of a variable in the device's memory

Within a component, I am facing the following situation: const [home, setHome]=useState(false) if(home){ return(<Redirect push={true} to="/" />); } setItem("isRegistered", resquest[0].user) setHome(true) The issue here is that ...

Unveiling the Ultimate Method to Package Angular 2 Application using SystemJS and SystemJS-Builder

I'm currently in the process of developing an application and I am faced with a challenge of optimizing the performance of Angular 2 by improving the loading speed of all the scripts. However, I have encountered an error that is hindering my progress: ...

Anticipate receiving a 'Type' returned by external library functions

I've recently started learning TypeScript and have encountered a situation where I need to assign a type to a variable that is returned from a third-party library function with its own type definition. For instance: import {omit} from 'lodash&ap ...

Creating a hyperlink dynamically within an Angular TypeScript file can be easily achieved

I am looking to create a dynamic hyperlink within the component (in the .ts file) using a for loop inside a function. I understand that this can be achieved by utilizing *ngFor loop in the template. For instance - <div *ngFor="let rec of item.R ...

Exploring the options variables within CLI commander Js action

As a newcomer to developing CLI apps, I've chosen to work with ts-node and commander. However, I'm currently facing a challenge in understanding how to access the options that users pass into my command action. program .version(version) .nam ...

`In NestJS Nested Schema, the @Prop decorator and mongoose options are not applied as expected

I'm currently working on constructing a Schema that includes a nested object. I am trying to define default values and required properties within the nested object, but it seems like the options I set are being ignored. task.entity.ts @Schema() expor ...

Typescript - any of the types imported from a module

Currently, my code looks like this: import * as Types from '../schema/types'; and I'm looking to achieve something along the lines of: let a: Types; This would signify that a should be one of the various types exported from the file types. ...

How to Override Global CSS in a Freshly Created Angular Component

My CSS skills are a bit rusty and I need some assistance with a project I'm working on. The project includes multiple global CSS files that have properties defined for different tags, such as .btn. However, these global CSS files are causing conflicts ...

TypeScript is throwing an error about a missing property, even though it has been defined

Within the PianoMK1Props component, there is a prop known as recording which accepts an object with specific properties. The structure of this object is defined like so(the state variable): const [recording, setRecording] = useState({ mode: "REC ...

In order for the expansion parameter to be successfully used, it must be either of tuple type or passed to the

const myFunction = function(arg1: number, arg2: number, arg3: number) {} const myFunction1 = function() {} const obj = { myFunction, myFunction1 }; type FuncType = typeof obj; function executeFunction<T extends keyof FuncType>(key: ...

My goal is to create a carousel using Vue 3 with the Composition API and TypeScript

Creating a carousel with Vue 3 and TypeScript has been quite challenging for me. I heard about using "vue-awesome-swiper" to build a carousel, but I couldn't find a tutorial on how to use it. Does anyone know how to utilize this tool effectively? Alte ...

What is the process for creating a node module with TypeScript?

So, with regards to the previous question about importing a module using typescript, here is a general answer: 1) Start by creating a blah.d.ts definition file. 2) Use the following code snippet: /// <reference path="./defs/foo/foo.d.ts"/> import ...

Angular service encountering duplicated arrays when retrieving data from Firebase using HTTP.get

While working on my Angular web application, I encountered a strange issue with duplicate arrays in the response from an HTTP get call to a Firebase realtime database. The Firebase setup includes a realtime database configured like this: Firebase data I ...

Creating a split hero section view using a combination of absolute/relative CSS techniques, Tailwind, and React

I'm in the process of creating a website using Nextjs, React, and TailwindCSS, and I aim to design a Hero section that resembles the one on the following website. https://i.sstatic.net/tq3zW.png My goal is to: Have a text title and buttons on the l ...

Adding a custom class to an ng-bootstrap tooltip can be accomplished by utilizing Angular's

Having trouble customizing an ng-bootstrap tooltip with a custom class. Markup: <i class="fa fa-info-circle" aria-hidden="true" [ngbTooltip]="infoTooltipTemplate" [tooltipClass]="info-tooltip" placement="top"></i> Stylesheet: .info-tooltip ...

Dynamic Assignment of Object Values Based on Enum Keys in Typescript

Check out this TS Playground for this piece of code. Dynamically Assigning Object Values Based on Enum Key I am attempting to achieve the following: in the interface iAnimals, each animal key in the enum Animals should have its associated interface value, ...

Using Angular service worker to pre-fetch video files

Issue arises when the service worker prefetches the entire video embedded on the page, leading to performance problems. My ngsw-config.json only contains configurations for local files, whereas the video is located on a different subdomain under /sites/def ...