Do I have to wait for the HTTP get request to access the fetched object property?

I am currently working with Angular and TypeScript on a dish-detail component that is accessed through 'dishes/:id'

The dish object returned has a property called components, which contains an array of objects with two properties:

  • id: type string
  • quantity: type number

I need to use the id property from components to fetch additional details from MongoDB (this functionality works on the back-end).

My issue is that I have to wait for getDish() to finish before I can execute getComponentDetails(). I have experimented with async/await, .then in ngOnInit and getDish(), as well as including logic like trackBy and if-else statements in the component's HTML file.

I am struggling to find a solution. Please refer to the comments in the code provided below.

Below is the content of dish-detail.component.ts:

export class DishDetailComponent implements OnInit{
  dish: Dish | undefined;
  id: string | undefined;
  component: any | undefined;
  components: any | undefined;
  currentComponent: any | undefined;
  componentDetails: [] = [];

  constructor(
    private route: ActivatedRoute,
    private location: Location,
    private dishService: DishService,
    private componentService: ComponentService,
  ) {}

  ngOnInit() {
    this.id = String(this.route.snapshot.paramMap.get('_id'));
    this.getDish();
    // executing getComponentDetails() here yields undefined error - dish not loaded yet
  }

  getDish(): void {
    this.dishService.getDishById(this.id!)
      .subscribe(dish => this.dish = dish);
    // executing getComponentDetails() here yields undefined error - dish not loaded yet
  }

  getComponentDetails(): void {
    console.log("in getComponentDetails...");
    this.dish!.components.forEach(function (value) {
      console.log(value.componentId);
    // here I will fetch component from ID and subscribe to variable
    // similar to getDish()
    })
  }

Here is the HTML content in dish-detail.component.html:

<div *ngIf="dish" class="mt-4">
  <div class="card">
    <div class="card-header">
      <h2>{{ dish.name | uppercase }} Details</h2>
    </div>

    <div class="card-body">
      <div class="mb-3">
        <label for="total-cost" class="form-label">Total Cost:</label>
        <span>{{ dish.totalCost }}</span>
      </div>

      <div class="mb-3">
        <label for="dish-name" class="form-label">Dish Name:</label>
        <input id="dish-name" [(ngModel)]="dish.name" class="form-control" placeholder="Name">
      </div>

      <div class="mb-3">
        <h3>Components:</h3>
        <div class="mb3" *ngFor="let component of dish.components">
          <div class="card" *ngIf="component">
            <p>test</p>
            <div class="card-body" class="mb-3">
              <h5 class="card-title">Id:{{ component.componentId }}</h5>
              <!-- here I would like to get properties from the component of id component.componentId,
              lets call it componentDetails-->
              <!-- like componentDetails.name -->
              <div class="card-text">
                <p>Quantity: {{ component.componentQuantity }}</p>
                <!-- other properties like componentDetails.price -->
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="d-flex justify-content-between">
        <a class="btn btn-warning" (click)="goBack()">Go Back</a>
        <a class="btn btn-primary" (click)="updateDish()">Update</a>
        <a class="btn btn-danger" (click)="deleteDish()">Delete</a>
      </div>
    </div>

    <div class="card-footer">
      <small class="text-muted">
        <p><b>Dish ID:</b> {{ dish._id }}
        <p><b>Created @</b> {{ dish.createdAt | date:'medium' }}</p>
        <p><b>Updated @</b> {{ dish.updatedAt | date:'medium' }}</p>
      </small>
    </div>
  </div>
</div>

I am looking for guidance on how to fetch data based on a property only after it has been fully loaded. How can I "pause" execution until then? Should I consider a different approach altogether?

Answer №1

Is there a way to retrieve data based on a specific property after it has been loaded?

To achieve this, you can create an observable stream from the source to your template model and then utilize the async pipe to subscribe in the template while also handling unsubscribe operations.

How can I handle "waiting" time?

Instead of waiting, you can create an imperative stream that processes the id and maps it to the view model by fetching values from observables via HTTPS requests.

Should I consider a different approach?

I advise against using nested subscribes as an alternative approach.

Stackblitz

import 'zone.js/dist/zone';
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import { of, delay, switchMap, forkJoin, map } from 'rxjs';

/** Mock services with delays */
const dishService = {
  getDishById(id: string) {
    return of({
      name: 'Very expensive caviar',
      totalCost: 1_000_000,
      components: [
        {
          id: 'jufbvjh',
        },
        {
          id: 'woehfjb',
        },
      ],
    }).pipe(delay(1000));
  },
};
const componentService = {
  getComponentById(id: string) {
    return of({
      componentId: id,
      componentQuantity: Math.random(),
    }).pipe(delay(1000));
  },
};

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule],
  template: `
    <ng-container *ngIf="vm$ | async as vm">
     <pre>{{ vm | json }}</pre>
    </ng-container>
  `,
})
export class App {
  name = 'Angular';

  vm$ = dishService.getDishById('jbvhbfr').pipe(
    switchMap((dish) =>
      forkJoin(
        dish.components.map((c) => componentService.getComponentById(c.id))
      ).pipe(
        map((componentInfo) => ({
          ...dish,
          components: [...componentInfo],
        }))
      )
    )
  );
}

bootstrapApplication(App);

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

How can I create a universal "Add" button in Angular that can be used across all child components?

Currently, I am working on a straightforward application featuring a toolbar at the top of the screen. Within this toolbar, there is a + button designated for adding content. The functionality of this + button changes based on which component is currently ...

Angular: accessing public properties

I have a component called "user.service.ts" that I want to share. import { Injectable } from '@angular/core'; import { Http, Headers, RequestOptions, Response } from '@angular/http'; import { AppConfig } from '../app.config&apos ...

The default value for the logged in user in Angular 7 is set to null when

In my login component, I have a form where users can enter their credentials and submit for authentication using the following function: this.auth.login(this.f.email.value, this.f.password.value) .pipe(first()) .subscribe( data ...

The issue of declaration merging and complications with nested node_modules

Here is the structure I am working with: @my/app node_modules @types/angular @types/angular-translate @my/library node_modules @types/angular The issue arises from the fact that @types/angular-translate extends the definitions of @types/angular ...

Refresh the context whenever the state object changes

Within my application, I am utilizing a PageContext to maintain the state of various User objects stored as an array. Each User object includes a ScheduledPost object that undergoes changes when a user adds a new post. My challenge lies in figuring out how ...

What is the most efficient way to find the sum of duplicates in an array based on two different properties and then return the

var data = [ { "amount": 270, "xlabel": "25-31/10", "datestatus": "past", "color": "#E74C3C", "y": 270, "date": "2020-10-31T00:00:00Z", "entityId": 1, "entityName": "Lenovo HK", "bankName": "BNP Paribas Bank", "b ...

Transitioning an NX environment to integrate ESM

My NX-based monorepo is quite extensive, consisting of half a dozen apps, frontend, backend, and dozens of libs. Currently, everything is set up to use commonjs module types, as that's what the NX generators have always produced. However, many librar ...

`Drizzle ORM and its versatile approach to SELECT statements`

Looking to improve the handling of options in a function that queries a database using Drizzle ORM. Currently, the function accepts options like enabled and limit, with potential for more options in the future. Here's the current implementation: type ...

Error in Typescript: The type 'string' cannot be assigned to the type '"allName" | `allName.${number}.nestedArray`' within the react hook form

Currently, I am tackling the react hook form with typescript and facing a challenge with my data structure which involves arrays within an array. To address this, I decided to implement the useFieldArray functionality. allName: [ { name: "us ...

`ng-apexcharts` causing unit test failures

I've been working on integrating apexcharts and ng-apexcharts into my home component. While I was able to get it up and running smoothly, it seems to be causing issues with my unit tests. Despite researching possible solutions, I haven't been abl ...

Subscribing to Observables in Angular Services: How Using them with ngOnChanges Can Trigger Excessive Callbacks

Consider the following scenario (simplified): Main Component List Component List Service Here is how they are connected: Main Component <my-list [month]="month"></my-list> List Component HTML <li *ngFor="let item in list | async>&l ...

Is there a way to customize the Color Palette in Material UI using Typescript?

As a newcomer to react and typescript, I am exploring ways to expand the color palette within a global theme. Within my themeContainer.tsx file, import { ThemeOptions } from '@material-ui/core/styles/createMuiTheme'; declare module '@mate ...

What method is the easiest for incorporating vue.js typings into a preexisting TypeScript file?

I currently have a functional ASP.NET website where I'm utilizing Typescript and everything is running smoothly. If I decide to incorporate jQuery, all it takes is running npm install @types/jQuery, and suddenly I have access to jQuery in my .ts file ...

Installing and running Node.js within a tomcat server

After creating a web application using Angular, Node/Express, and MySQL, I faced an issue with deployment. My Angular app is running on a tomcat server connected to multiple PCs, but now I need to also deploy my backend (Node.js/Express.js) on the same s ...

Incorporating an Angular Application into an Established MVC Project

I am working on an MVC project within an Area of a larger solution. My goal is to incorporate an Angular App into this area and integrate it with my MVC project. The catch is that this is not a .Net Core Mvc project. How can I configure my project to utili ...

Tips for changing the name of a directory in an Angular 6 application

Looking for guidance on renaming a folder in an Angular 6 project's components directory. Is there a safe way to do this without causing any issues, or is it as simple as just changing the name of the folder? Using Visual Studio Code as my IDE. ...

Having trouble with TypeScript Library/SDK after installing my custom package, as the types are not being recognized

I have created my own typescript library using the typescript-starter tool found at . Here is how I structured the types folder: https://i.stack.imgur.com/igAuj.png After installing this package, I attempted a function or service call as depicted in the ...

Allow for an optional second parameter in Typescript type definition

Here are two very similar types that I have: import { VariantProps } from "@stitches/core"; export type VariantOption< Component extends { [key: symbol | string]: any }, VariantName extends keyof VariantProps<Component> > = Extra ...

What is the substitute for <center> tag in AngularJS?

Error: Template parse errors: 'center' is not a recognized element: 1. If 'center' is supposed to be an Angular component, make sure it is included in this module. 2. To permit any element, add 'NO_ERRORS_SCHEMA' to the ' ...

Minimize the cyclomatic complexity of a TypeScript function

I have a typescript function that needs to be refactored to reduce the cyclometric complexity. I am considering implementing an inverted if statement as a solution, but it doesn't seem to make much of a difference. updateSort(s: Sort) { if (s.ac ...