英文:
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.
英文:
> 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);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论