How can we simultaneously execute multiple HTTP requests in Angular 6 by leveraging the power of forkJoin and ngrx?

Current Situation

In the realm of my angular6 application, I find myself juggling three distinct categories: catA, catB, and catC. Each of these categories requires data retrieval from 3 separate APIs. Upon selecting any category, the CategoryDetailsComponent is loaded, triggering the dispatching of an action (LoadCategoryDetails).

To tackle this, I have incorporated the utilization of forkJoin to handle parallel API calls within the service, coupled with a resolver to ensure that all calls are completed before loading the component.

Anomaly

  • Upon selecting catA (or after a page reload), the categoryNames array appears empty.
  • Selecting catB (following the second routing) displays the previous category's list (catA) in the CategoryNames array.

The discrepancy may arise due to a delay in one of the API calls, possibly indicating improper configuration of the resolver.

Query

How can the effects and resolver be configured effectively?

What is the best approach to implement forkJoin for multiple API calls and forward the retrieved data to the component?

Code Analysis

  1. Execute action dispatch and subscribe to selector

    ngOnInit() {
        const id = parseInt(this.route.snapshot.paramMap.get('categoryId'), 10);
        this.store.dispatch(new fromCategory.LoadCategoryDetails(id));
    
        this.store.select(getCategoryDetails)
                  .subscribe((data) => {
                    this.categoryDetails = data[0];
                    this.journeys = data[1];
                    this.categories = data[2];
                  });
    
        // extract only category name
        // issue alert
        this.categories.forEach( category => {
          this.categoryNames.push(category.name);
        });
    }

  2. Effects setup (track action triggers and invoke service)

    @Effect()
    loadCategoryDetails$ = this.actions$.pipe(
        ofType<fromCategory.LoadCategoryDetails>(CategoryActionTypes.LoadCategoryDetails),
        switchMap((action) => {
        return this.categoryService.getCategoryDetails(action.payload).pipe(
            map(data => new fromCategory.LoadCategoryDetailsSuccess(data))
        );
        })
    );

  3. Service function orchestrating multiple calls using forkJoin

    import { forkJoin } from 'rxjs';
    
    getCategoryDetails(categoryId) {
        const categoryDetails = this.http.get(url);
        const journeys = this.http.get(url);
        const courses = this.http.get(url);
    
        return forkJoin([categoryDetails, journeys, courses]);
    }

  4. Resolver functionality implementation

    export class CategoryDetailsResolver implements Resolve<any> {
    
        constructor(
            private categoryService: CategoryService,
            private router: Router) {}
    
        resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
            const categoryId = route.paramMap.get('categoryId');
            return this.categoryService.getCategoryDetails(categoryId);
        }
    }

Your insights are greatly appreciated.

Answer №1

Try revising your code to eliminate the use of route.snapshot and check if that resolves the issue.

ngOnInit() {
this.route.data.subscribe((data) => {

if(data) {
 this.store.dispatch(new fromCategory.LoadCategoryDetails(data.id));

 this.store.select(getCategoryDetails)
          .subscribe((data) => {
            this.categoryDetails = data[0];
            this.journeys = data[1];
            this.categories = data[2];

 this.categories.forEach( category => {
  this.categoryNames.push(category.name);
  });
});

}

});

}

Answer №2

It seems like your implementation of forkjoin is on the right track. However, there is a potential issue in your code where you are iterating through the categories outside of the getCategoryDetails callback. This could lead to problems due to the asynchronous nature of the operation. To ensure that you have access to the categories before iterating through them, it's recommended to move the iteration code inside the successful callback function.

ngOnInit() {
    const id = parseInt(this.route.snapshot.paramMap.get('categoryId'), 10);
    this.store.dispatch(new fromCategory.LoadCategoryDetails(id));

    this.store.select(getCategoryDetails)
              .subscribe((data) => {
                this.categoryDetails = data[0];
                this.journeys = data[1];
                this.categories = data[2];

this.categories.forEach( category => {
      this.categoryNames.push(category.name);
    });
              });

    // Ensure that category names are only filtered after successful retrieval
    // problem

}

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

Leveraging async-await for carrying out a task following the deletion of a collection from a mongodb database

Trying to implement async await for executing an http request prior to running other code. Specifically, wanting to delete a collection in the mongodb database before proceeding with additional tasks. This is what has been attempted: app.component.ts: ...

What is the best way to implement individual error handling for each function within combineLatest?

I'm looking for guidance on how to handle errors in each function within this `combineLatest` operation. Check out the code snippet below: const combined = combineLatest( this.myservice1.fn1(param), this.myservice2.fn2(), this.myservice3.fn3() ...

Can you please verify the most recent updates for Bootstrap and Syncfusion in my Angular project?

Could someone help me figure out when the bootstrap and syncfusion libraries were last updated in my Angular project? I'm having difficulty finding this information. ...

Is it possible to create a click event for a mat-icon within a mat form field (either in the matprefix or matsuffix)?

I am working with a mat-form-field and have incorporated a custom mat-icon within it as a matprefix. However, I am now looking to create a click method for that matprefix icon. Despite my attempts to write a click method, it does not seem to be functioning ...

Using currency symbols in Angular 2

I'm currently in Australia and trying to display some currency values. I have the following code: {{ portfolio.currentValue | currency : 'AUD' : true : '4.0' }} However, the result I am getting is A$1,300,000. Is there a way to c ...

How to exit a dialog in an Angular TypeScript component with precision

Hey there, I'm attempting to close a dialog from the component by specifying the path in .angular-cli.json and calling the function. However, it seems that despite my efforts, the dialog isn't closing and the redirection isn't happening. He ...

Has anyone tried integrating Reveal JS with Angular 8?

Encountering a problem with the integration of Reveal JS in an Angular component. Despite being initialized after DOM processing, it is not displaying anything. What is the appropriate time to initialize the reveal library? Is there a way to incorporate ...

Unlock the Full Potential of TypeScript: Seamless Export of Classes and Functions

In my AngularJS project, I have a separate JavaScript file where I declare prototype functions. Here's an example: function lastConv(){ this.item1="2" this.message="hello" ...... } lastConv.prototype.setupfromThread(data) { this.currentBox = dat ...

Injecting Window into Angular 2.1.0: A Step-by-Step Guide

Previously, in the earlier RC versions of Angular 2, I was able to easily inject the window object by including {provide: Window, useValue: window} In the providers array. However, after updating to the latest stable release of Angular 2 (2.1.0), this no ...

What is the reason behind Angular 6 producing my service inside the directory "e2e/app"?

When creating a new service in Angular 6 using the command: ng generate service <service-name> angular.json { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "t ...

What is the best way to ensure a specific row remains at the bottom of an Angular table with Material when sorting?

My data table contains a list of items with a row at the end showing the totals. | name | value1 | value2 | --------------------------- | Emily | 3 | 5 | | Finn | 4 | 6 | | Grace | 1 | 3 | | TOTAL | 8 | 14 | I&apos ...

Subject.next() not triggering Observable on value change

I'm currently working on developing an autocomplete feature using Observable and Subject in Angular. However, I've run into an issue where the service method is not triggered when the Subject object's value changes. Below is a snippet of my ...

Differentiating body classes in Angular 5

I am working on a project with both a login screen and a dashboard screen. The body classes for these screens are different, as shown below: <body class="hold-transition skin-black-light sidebar-mini" > // for dashboard <body class="hold-transi ...

When clicking, clear the selected items and avoid the function from repeatedly executing

I am currently facing issues with implementing mat-select-autocomplete in my project. Firstly, I have noticed that the function's (selectionChange)="getSelectedOptions($event)" is triggered every time I click on mat-select-autocomplete. Is there a wa ...

I need a way to call a function in my Typescript code that will update the total value

I am trying to update my total automatically when the quantity or price changes, but so far nothing is happening. The products in question are as follows: this.products = this.ps.getProduct(); this.form= this.fb.group({ 'total': ...

Ways to specify certain columns for presentation in Angular Material Table

When retrieving data from a WebApi with 10 columns, I am utilizing Angular Material Grid on the Front-End. user: User; dataSource: UsersDataSource; displayedColumns = ['UserName', 'RoleName', 'ISShared', 'IsDeleted'] ...

Can multi-page applications be developed using Angular?

As I contemplate developing a food ordering application similar to Zomato, I have observed that Angular-like routing is used on certain pages, specifically during the ordering process after selecting a restaurant. Unlike other sections where server routing ...

A guide on using hyperlinks to scroll to a targeted position in an Angular application

Is there a way to implement scrolling to a specific position in Angular using hyperlinks? In HTML, it can be implemented like this: <a href="#google"></a> <div id="google"></div> Can anyone provide guidance on h ...

Using electron cookies in Angular involves integrating Electron's native cookie functionality into an

I am currently dealing with electron and looking to implement cookies conditionally in my project. If the application is built using electron, I want to utilize Electron Cookies; otherwise, I plan to use Angular Cookies. However, I'm encountering diff ...

It is not possible to bind an attribute to an element that already has a Bootstrap class applied to it

Currently, I am working on an Angular 2 web application and incorporating bootstrap for styling purposes. Within the app, there is a small triangle that needs to alternate between being visible and invisible. Here is the code snippet representing this elem ...