How can we efficiently link data to custom objects (models) within a different class while fetching data from the server using the http.get() method in Angular CLI?

Currently in the process of developing an Angular-Cli application that involves multiple models with relational data tables. When fetching data from the server, I need to map this data to corresponding model objects.

I've experimented with creating a single model to represent the database view by merging two different models. However, I found this approach cumbersome and somewhat absurd for my application.

export class Employee{
id:number;
fullName:string;
department: Department;
}

export class Department{
deptId:number;
name:string;
}

#within my service
<-- department table | json -->
[
{deptId: 1, name: "IT"},
{deptId: 2, name: "HR"},
{deptId: 3, name: "Finance"}
]

<-- employee table | json -->
[
{id: 1, fullName: "George W Bush", deptId:1},
{id: 2, fullName: "Barack Obama", deptId:2},
{id: 3, fullName: "Donald Trump", deptId:3},
]

<-- data retrieved from view | json -->
[
{id: 1, fullName: "George W Bush", deptId:1, name: "IT"},
{id: 2, fullName: "Barack Obama", deptId:2, name: "HR"},
{id: 3, fullName: "Donald Trump", deptId:3, name: "Finance"},
]


employees: Employee[]
getData():Observable<Employee[]>{
    return this.http.get<Employee[]>(this.stringUrl).subscribe(data=>{
    employees = data;
});
}

<ul *ngFor="let employee of employees">

    <li>employee.fullName}}
         <ul>
            <li>{{employee.department}}</li>
         </ul>
    </li>

</ul>

1. George W Bush
   a.IT
2. Barack Obama
   b.HR
3. Donald Trump
   c.Finance

Answer №1

After considering the comments, my suggestion would be to enhance the backend to retrieve Employee objects already linked with the department name using an SQL JOIN. Alternatively, you can implement the following workaround:

Component Template

In this approach, we are utilizing the template to manage the subscription to the observable by employing an async pipe instead of subscribing within the component itself.

<ul *ngFor="let employee of employees$ | async">
  <li>
    {{employee.fullName}}
    <ul>
      <li>{{employee.department.name}}</li>
    </ul>
  </li>
</ul>

Component

export class AppComponent {
  employees$: Observable<Employee[]>;

  constructor(private readonly employeeService: EmployeeService) {
    this.employees$ = this.employeeService.getData();
  }
}

Service

This service ensures that departments are fetched first before creating a map to pass to the getEmployees() method. By leveraging rxjs's switchmap, the getData() function will return the desired Employee[].

interface EmployeeResponse {
  id: number;
  fullName: string;
  deptId: number;
}

export class Employee {
  id: number;
  fullName: string;
  department: Department;
}

export class Department {
  deptId: number;
  name: string;
}

const employeesUrl = 'http://localhost:4201/employees';
const departmentsUrl = 'http://localhost:4201/departments';

@Injectable({
  providedIn: 'root',
})
export class EmployeeService {
  constructor(private readonly http: HttpClient) {}

  getData(): Observable<Employee[]> {
    return this.getDepartments().pipe(
      switchMap(departmentsMap => this.getEmployees(departmentsMap)),
    );
  }

  getDepartments(): Observable<Map<number, Department>> {
    return this.http
      .get<Department[]>(departmentsUrl)
      .pipe(
        map(
          departments =>
            new Map<number, Department>(
              departments.map(department => [department.deptId, department]),
            ),
        ),
      );
  }

  getEmployees(departmentsMap) {
    return this.http.get<EmployeeResponse[]>(employeesUrl).pipe(
      map(employeesResponse => {
        return employeesResponse.map(employeeResponse => {
          const employee = new Employee();
          employee.id = employeeResponse.id;
          employee.fullName = employeeResponse.fullName;
          employee.department = departmentsMap.get(employeeResponse.deptId);
          return employee;
        });
      }),
    );
  }
}

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

Accordion symbol for adding or subtracting

Looking for a way to change the Toggle text in my angular 7 application accordion to images or content displaying a + sign for collapse and - for expand. I need to achieve this using CSS in my SCSS stylesheet so that I can later change the color of the sig ...

Mapping JSON to interface in Angular 7: A step-by-step guide

I am currently working with angular7 and I have a requirement to map a json object to my interface. My goal is to create a function that can accurately map the fields of the json object to the corresponding properties in the interface. Additionally, if the ...

In Rxjs, Subscribe now emits individual items one at a time instead of emitting a list all at once

I've encountered an issue in my Angular 4 application while working with Rxjs and I can't seem to figure out the behavior. Here's a snippet of my code: this.server.get("incidents") //http get resource .flatMap((res) => res.value) //the ...

How can I retrieve image files from locations outside the Angular 5 app or assets directory?

One of the features in my app allows users to upload images. I recently learned that it's best practice to store these image files outside of the app or assets folder since those folders are compiled. Here is a snapshot of my app's folder structu ...

Error encountered with react-query and UseQueryResult due to incorrect data type

I'm currently implementing react-query in my TypeScript project: useOrderItemsForCardsInList.ts: import { getToken } from '../../tokens/getToken'; import { basePath } from '../../config/basePath'; import { getTokenAuthHeaders } fr ...

Following a docker run command, Docker undergoes an automatic shutdown process

I am currently working on an Angular 7 application and I'm looking to deploy it using Docker. I have created a Dockerfile in the root folder, but when I attempt to run Docker, it seems to terminate unexpectedly. Below is the content of my Dockerfile: ...

Having trouble adding npm package to Angular project due to npm error ERESOLVE?

I encountered this error while attempting to install any package with npm. I have attempted to clear the cache and reinstall node itself, but none of these methods have worked. -- Error message D:\Electrolux KB\Electrolux-KnowledgeBase.eg_v2> ...

TSLint is encountering the error code TS2459: The module "@azure/core-tracing" claims to have a local declaration of "Span" but does not export it, along with additional errors

I'm completely lost on how to tackle this error. The message I'm getting doesn't provide much insight, other than indicating an issue with the installation of '@azure/ai-text-analytics'. I've gone through the process of uninst ...

In Angular, what is the process of dynamically updating an input label?

Within my form, I have two input fields - one is a "select" and the other is an "input". Utilizing Angular, my goal is to dynamically change the text label of the second input based on the selection made in the first input. ...

Executing a function within the same file is referred to as intra-file testing

I have two functions where one calls the other and the other returns a value, but I am struggling to get the test to work effectively. When using expect(x).toHaveBeenCalledWith(someParams);, it requires a spy to be used. However, I am unsure of how to spy ...

Ways to activate auto completion without using a string

Can anyone assist us with the tinymce editor? We have implemented an auto completion feature using a plugin from TinyMCE's documentation, but we are having trouble changing the triggering behavior. Currently, it only suggests options when "@" is typed ...

What is the best way to dynamically update styleUrls or style properties in Angular?

One of my goals is to give users the ability to customize colors and certain styles within my Angular application. I am thinking about creating a structure like this: Structure: component-one   folder-with-css-files     style-for-component-1-fo ...

Angular has got us covered with its latest feature - combining Async Await with an EventListener

I have been facing this issue for the past day and need help creating a specific scenario: <img [src]="userdp | async" /> In my component.ts file, I want to include only this line: this.userdp = this._userService.getUserDp(); Here is the ...

Creating a unified environment variable for Angular 2 and ASP.NET Core MVC: A comprehensive guide

In my ASP.NET Core MVC project, I am utilizing an Angular 2 application. Both the Angular 2 app and the Startup.cs file contain code that is specific to different environments. For example, using http://localhost as the web service URL during development ...

Guide to incorporating @types/module with the corresponding npm module that has type definitions available

This is an example of a module I am currently utilizing in my project. I have come across TypeScript type definitions for the npm module polylabel, which can be found at https://github.com/mapbox/polylabel. When I run npm install --save @types/polylabel, ...

Parent component interacting with child component

In my application, I have a header component along with registration and login components. The selector of the header component is used in both the login and registration components. There is also a button in the header that displays as a login button if t ...

Commitments, the Angular2 framework, and boundary

My Angular2 component is trying to obtain an ID from another service that returns a promise. To ensure that I receive the data before proceeding, I must await the Promise. Here's a snippet of what the component code looks like: export class AddTodoCo ...

Is it possible to dynamically create an interface using an enum in TypeScript through programmatically means?

Recently, I defined an enum as shown below: enum EventType { JOB, JOB_EXECUTION, JOB_GROUP } Now, I am in need of creating an interface structure like this: interface EventConfigurations { JOB: { Enabled?: boolean; }; JOB_EXECUTION: { ...

Creating adaptable rows and columns with Angular Material's data table feature

My approach to rendering dynamic rows and columns using a basic table was successful: <tbody> <tr *ngFor="let row of data"> <td *ngFor="let val of row"> {{ val }} </td> </tr> </tbody> </ ...

Scrolling the mouse wheel on Angular 2 Typescript Highcharts Highmap

I'm currently exploring if it's possible to subscribe to the zooming event in a Highmap using Angular 2 with Typescript for Highcharts/Highmap, or possibly even to a mouse wheel scrolling event. @HostListener('scroll', ['$event&a ...