Obtain multiple class instances through HTTP-Get in Angular

Initially, explaining this with my actual code can be confusing, so I'll simplify the issue using a smaller example.

Imagine my project retrieves data from 2 tables on the server, employeeDetails and employeeNames.

employeeNames: This table consists of three columns - employeeNumber, firstName, and lastName. It contains a list of all employees with their unique employee number, first name, and last name.

employeeDetails: This table is where I perform httpGet and httpPost requests from my website. Let's say this table includes these fields:

  • employee: Accepts the employee number as input
  • qualifications: Allows users to input various qualifications as a string
  • supervisor: Requires the supervisor's employee number, not the name
  • manager: Needs the manager's employee number, not the name

While this setup exists in the backend, the frontend interface for employeeDetails includes additional members, making it more complex.

The Angular interface on the frontend appears as follows:

export interface employeeDetails
{
    employee: number;
    qualifications: string;
    supervisor: number;
    manager: number;
    employeeName: string;
    supervisorName: string;
    managerName: string;
}

I use httpGet to fetch data from the backend API. After obtaining data from both tables, I have a function that populates the extra fields in the employeeDetails interface.

Controller

[HttpGet("[action]")]
public IActionResult getEmployeeNames()
{
        using (var empApp= new EmployeeTable())
        {
            var empNames = new List<employeeNames>();
            empNames = empApp.employeeNames.ToList();
            return Json(empNames);
        }
}

[HttpGet("[action]")]
public IActionResult employeeDetails()
{
        using (var empApp= new EmployeeTable())
        {
            var empDetails = new List<employeeDetails>();
            empDetails = empApp.employeeDetails.ToList();
            return Json(empDetails);
        }
}

Service

  getEmployeeNames(): Observable<employeeNames[]> {
    return this.http.get<employeeNames[]>(this.baseUrl + 'api/employeecontroller/getEmployeeNames')
    .pipe(catchError(this.handleError('getItems', [])));
  }

  getEmployeeDetails(): Observable<employeeDetails[]> {
    return this.http.get<employeeDetails[]>(this.baseUrl + 'api/employeecontroller/getEmployeeDetails')
    .pipe(catchError(this.handleError('getItems', [])));
  }

Component

getEmployeeInfo() {
    this.employeeService.getEmployeeNames()
      .subscribe(data => this.employeeNames = data);
    this.employeeService.getEmployeeDetails()
      .subscribe(data => this.employeeDetails = data);

    fillEmployeeDetails();
}

fillEmployeeDetails() {
    this.employeeDetails.forEach(elem => {
        let emp = this.employeeNames.find(employee => {
            return (employee.employeeNumber === elem.employeeNumber);
        });
        let sup = this.employeeNames.find(supervisor => {
            return (supervisor.employeeNumber === elem.supervisor);
        });
        let man = this.employeeNames.find(manager=> {
            return (manager.employeeNumber === elem.manager);
        });

        elem.employeeName = emp.firstName + " " + emp.lastName;
        elem.supervisorName= sup.firstName + " " + sup.lastName;
        elem.managerName= man.firstName + " " + man.lastName;

    });
}

However, this function fails when called because it runs before the complete employeeNames table is fetched. Consequently, .find() returns null values for many employee numbers, leading to unexpected results.

MY INQUIRY

Should I consider using async/await and .toPromise() instead of subscribing to the service to await data fetching completion, or is there a better approach?

Any guidance or insights are highly appreciated. Thank you!

Answer №1

Subscribing to the observable is necessary to trigger the HTTP request effectively. Additionally, it is important to note that calling this.fillEmployeeDetails(); in the code snippet won't work as intended because the request is asynchronous and will take some time for the data to return. The line of code where you call this.fillEmployeeDetails;, however, will execute immediately after sending the request.

Once the data returns, the callback function inside subscribe will be invoked with the response from the request. It is crucial to call this.fillEmployeeDetails(); within the subscribe block to handle the received data properly.

One challenge you may encounter is determining when both requests have completed so that you can start your fill... function.

The best approach is to use an rxJs operator like forkJoin, which, in this scenario, operates similarly to Promise.all(). This means that the callback in the subscribe method will only be triggered once all observables (requests) have been executed successfully.

In essence, your component code should appear as follows:

getEmployeeInfo() { // requests extracted for clarity
    const employeeNamesRequest = this.employeeService.getEmployeeNames();
    const employeeDetailsRequest = this.employeeService.getEmployeeDetails();

    forkJoin([employeeNamesRequest, employeeDetailsRequest])
        .subscribe(data => {
            this.employeeNames = data[0];
            this.employeeDetails = data[1];
            this.fillEmployeeDetails();
        })
}

fillEmployeeDetails() {
    this.employeeDetails.forEach(elem => {
        let emp = this.employeeNames.find(employee => {
        return (employee.employeeNumber === elem.employeeNumber);
    });
    let sup = this.employeeNames.find(supervisor => {
        return (supervisor.employeeNumber === elem.supervisor);
    });
    let man = this.employeeNames.find(manager=> {
        return (manager.employeeNumber === elem.manager);
    });

    elem.employeeName = emp.firstName + " " + emp.lastName;
    elem.supervisorName= sup.firstName + " " + sup.lastName;
    elem.managerName= man.firstName + " " + man.lastName;

    });
}

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

Troubleshooting problem with Angular2 installation

Can someone please shed light on the current problem I am facing with the updated version of angular-cli? It was running smoothly earlier but now it keeps showing an error message saying "The "@angular/compiler-cli" package was not properly installed." An ...

How can we pass the onClick prop from a child component to a parent component in React with Typescript?

Currently, I am utilizing React along with TypeScript. I am curious about the process of passing an event from the parent component to a child component using props. Here is an example for better understanding: parent.tsx const ParentComponent: React.F ...

Following the build in Angular, it only displays the index.html file and a blank screen

According to the information on Angular's official website, running the "ng build" command should generate files in the dist folder ready for hosting. However, after running this command, the index.html file is empty except for the page title. When yo ...

Having trouble retrieving documents from a nested collection in Firebase

I am attempting to retrieve all documents from Firebase that are based on a query. Here is my current firebase structure: https://i.stack.imgur.com/tXrX8.png Even though I have two documents inside the "ListaFavorite" collection, when I check using empty ...

Navigate smoothly through Angular components without any page reloads

Here is a simplified version of my current setup: <app-header></app-header> <app-search></app-search> <router-outlet></router-outlet> <app-footer></app-footer> Within the router-outlet, I have two component ...

Guide on integrating Angular and Node.js for ESC/POS protocol integration

Apologies for any errors in my English language. I have an Angular front-end, a Node.js server, and a thermal printer. In order to establish communication with the thermal printers from Angular using the ESC/POS protocol, I created a Node.js server. Curr ...

Calculating the Angular Sum of Multiple Input Fields

There are multiple input fields on this page. <div class="form-group w-100"> <label class="col-md-3 text-left" for="">Box 2</label> <input class="form-control ml-2 mr-2" [value]="MenuBox2" [style.backgrou ...

TypeScript abstract class generics: `Class<?>` type

When working with TypeScript, I often utilize a Java-like type called Class: interface Class<T = void> { new(...args: any[]): T; } Unfortunately, this type doesn't seem to be compatible with abstract classes: abstract class Bar {} class ...

What is the best way to inject services into non-service class instances in Angular 2?

Here is my current approach, but I'm curious about the recommended practice for working with Angular2? ... class MultitonObject { _http: Http; constructor (appInjector: Injector) { this._http = appInjector.get(Http); } } var ap ...

Set up local npm packages for easy access by different projects

Can someone explain to me how npm works compared to Maven (I have a background in Java) when it comes to package management? I've developed a generic component using Angular 4 that will be used across multiple projects. I've published it to our n ...

What steps can I take to ensure that AstroJS components do not conceal SVG elements when the SVG is incorporated into another file with client:load?

Currently, I am developing a weather application using Astro.js in conjunction with React. One of the features includes an SVG component that serves as the project logo and is implemented in the initial page loader. Upon the page loading, the SVG functions ...

Where should the transformation of server response data into a format that the component can interpret be done within the NgRx framework?

New to NgRx and feeling a bit confused at the moment. I have a basic component that displays a list of objects, in this case Orders, retrieved from the backend using an Effect. The challenge is to transform the response from the backend into a simplified l ...

Using RxJS pubsub to transform an Observable<any> into a string or object

My current pubsub service implementation is as follows: export class PubSubService { subjects: Map<string, Subject<any>> = null; constructor() { this.subjects = new Map<string, Subject<any>>(); } publish(data: { key: ...

Struggling to overcome the TS2322 error when assigning generic values

I am currently working on developing higher-order React components that will include default values for components labeled as "named". Here is a basic implementation example: type SomeProps = { a: string } type Variants = 'variantA' | 'var ...

"Encountering difficulties while setting up an Angular project

I am currently working on setting up an Angular project from scratch. Here are the steps I have taken so far: First, I installed Node.js Then, I proceeded to install Angular CLI using the command: npm install -g @angular/cli@latest The versions of the ...

Difficulty setting up AngularFire in Ionic application

Seeking assistance for the installation of AngularFire in a Ionic 6 project. Encountering an error message: Packages installation failed, see above. Below is the setup details: >> ionic info Ionic: Ionic CLI : 7.0.1 (C:&bsol ...

Typescript not being transpiled by Webpack

As I set out to create a basic website, I opted to utilize webpack for packaging. TypeScript and SASS were my choice of tools due to their familiarity from daily use. Following the documentation at https://webpack.js.org, I encountered issues with loaders ...

Maximizing Efficiency of Vendor Bundle in Angular 2 with Webpack

My MEAN application's client side is built in Angular2 with Webpack, but I'm facing slow loading times due to a large vendor modules JS file. Is there a way to optimize this situation? I want to separate the vendor's JS file. Below is my we ...

Sending template reference from one Angular component to another

I have a main grid component that includes smaller grid-item components. The majority of these grid items navigate to a specific route when clicked. However, there is one particular item that should open a modal window instead of navigating. Is there a wa ...

Identify the signature of a callback function during runtime

My goal is to pass different callback functions as arguments and have them called with the proper parameters. Here is a simplified example of how it should work. However, determining if process instanceof ITwo makes no sense and I haven't found an ex ...