HTTP获取来自提取的对象属性的请求 – 我需要等待吗?

huangapple go评论121阅读模式
英文:

HTTP get request from fetched object property - I need to wait?

问题

dish-detail.component.ts文件中,您需要确保在调用getComponentDetails()方法之前等待getDish()方法完成。您可以使用ngOnInit钩子来确保在执行getComponentDetails()之前获取了菜肴数据。以下是您可以尝试的更改:

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

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

  ngOnInit() {
    this.id = String(this.route.snapshot.paramMap.get('_id'));
    this.getDishAndFetchComponents();
  }

  getDishAndFetchComponents(): void {
    this.dishService.getDishById(this.id!).subscribe((dish) => {
      this.dish = dish;
      this.getComponentDetails();
    });
  }

  getComponentDetails(): void {
    console.log('in getComponentDetails...');
    if (this.dish && this.dish.components) {
      this.dish.components.forEach((component) => {
        // Assuming you have a method to fetch component details by ID from MongoDB
        this.componentService.getComponentById(component.componentId).subscribe((componentDetails) => {
          this.componentDetails.push(componentDetails);
        });
      });
    }
  }
}

在这个修改后的代码中,我们使用getDishAndFetchComponents()方法来获取菜肴数据并等待它完成,然后再调用getComponentDetails()来获取组件的详细信息。这确保了在获取组件详细信息之前等待菜肴数据加载完成。

另外,请确保您的ComponentService具有一个方法getComponentById(),它可以通过组件的ID从MongoDB中获取组件详细信息。

然后,您可以在HTML模板中循环遍历componentDetails数组来显示组件的详细信息。

英文:

Using Angular and TypeScript, I have a dish-detail component -> dishes/:id

The fetched dish has a property called components (not good I didn't know Angular use this term) with an array of two properties:

  • id: type string
  • quantity: type number

I want to use the property id of components to fetch components from MongoDB (works on back-end).

My problem is that I have to wait for getDish() is done before I can run getComponentDetails(). I have tried async/await and .then on ngOnInit and getDish(), stuff in the component.html like trackBy, if then.

I just can't figure it out. See comments in provided code.

Here is 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()
    })
  }

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>

How can I fetch data based on property after it loaded? How do I "wait"? Do I need a completely different approach?

答案1

得分: 1

Create an observable stream from source to your template model then using async pipe to subscribe in the template (this also takes care of unsubscribing).

So you don't "wait" but create the (imperative as opposed to declarative) stream that will take the id and map to the view model taking in values from observable https along the way.

The alternate approach I don't recommend is doing nested subscribes.

Stackblitz

英文:

> How can I fetch data based on property after it loaded?

Create an observable stream from source to your template model then using async pipe to subscribe in the template (this also takes care of unsubscribing).

> How do I "wait"?

So you don't "wait" but create the (imperative as opposed to declarative) stream that will take the id and map to the view model taking in values from observable https along the way.

> Do I need a completely different approach?

The alternate approach I don't recommend is doing nested subscribes.

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);

huangapple
  • 本文由 发表于 2023年8月10日 22:28:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76876701.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定