我有一个服务,用于通知类别数组已填充(通过调用应用程序引导程序中的 API)。一旦这些类别准备就绪,我必须针对数组中包含的每个类别启动 API 调用,以查找每个类别的数据详细信息,然后将其显示在同一页面的不同部分。
通知可以以两种不同的方式发生,在应用程序第一次加载结束时(仅启动一次)或每次浏览应用程序的用户到达页面并且类别数组已被填充时。
这是组件代码。
export class CategoriesComponent implements OnInit, OnDestroy {
tagsCategories: TagCategory[]|null = null;
dateRangeTags: {start: Date, end: Date};
component_destroy = new Subject<void>();
constructor(...)
{
const d = new Date();
this.dateRangeTags = {start: this.commonFunc.getOneMonthAgo(d), end: d};
}
ngOnInit() {
console.log('init', this.tagsCategories);
this.loader.loadingOn();
if (this.sharedDataService.getTagCategories().length > 0) {
//categories have already been loaded
this.sharedData.notifyTagsCategoriesReady();
}
this.sharedData.categoriesAvailable$
.pipe(
tap(() => {
const categories = this.sharedData.getTagCategories();
for (const category of categories) {
category.date_range_request = {...this.dateRangeTags};
}
this.tagsCategories = categories;
console.log('tap side effect', this.tagsCategories);
this.loader.loadingOff();
}),
filter((v,i) => this.tagsCategories !== null && this.tagsCategories.length > 0),
switchMap(
() => from(this.tagsCategories!).pipe(
mergeMap((category: TagCategory) =>
this.fetchTagsCategories(category.date_range_request!, category)
.pipe(
tap({
next: (categories: TagCategory[]) => {
if (categories.length > 0) {
const cat = categories[0];
if (cat.id === category.id) {
category.tags_plots = cat.tags_plots;
}
}
},
error: (error) => {
category.spinner = false;
},
complete: () => {
category.spinner = false;
}
}),
catchError((error) => throwError(() => error))
)
)
)
)
)
.subscribe({
next: (val) => {
console.log('final next', val);
},
error: (error: string) => {
this.errorHandler.displayErrorDialog(error);
},
complete: () => {}
})
}
}
这是服务中的主题,也是我调用来通知两种不同场景中类别可用性的函数。
export class SharedDataService {
categories: TagCategory[] = [];
private _categoriesAvailable = new Subject<boolean>();
categoriesAvailable$ = this._categoriesAvailable.asObservable();
//this is called when the categories are fetched from the server
setTagCategories(tagCategories: TagCategory[]) {
this.categories = tagCategories;
console.log('Set tag categories');
this._categoriesAvailable.next(true);
}
//this is called when the user visit the categories page and the array is already loaded
notifyTagsCategoriesReady() {
console.log('notifyTagsCategoriesReady');
this._categoriesAvailable.next(true);
}
getTagCategories() {
return this.categories;
}
}
在组件视图中,我插入了一个保护,如果类别数组尚未初始化或为空,则不会显示各个部分。
<h1 class="nom">{{ 'categories.title' | translate }}</h1>
@if (tagsCategories && tagsCategories.length > 0) {
@for (tagCategory of tagsCategories; track tagCategory.id) {
<!-- build each section -->
}
当应用程序在类别页面上完全重新加载,然后应用程序引导时,一切都会正常工作,但如果您导航到其他页面,然后返回到该页面,即使 tap 操作符中的 console.log 指示数组已正确填充,也不会显示各个部分。此外,每次您重新访问该页面时,请求都会成倍增加,就好像每次都添加相同的订阅一样,如果数组包含三个元素,那么每次我重新访问该页面时都会添加 3 个请求。我还尝试插入一个 takeUntil 通知组件的销毁,但在这种情况下,订阅只在第一次有效,之后永远不会重新创建,即使打印了 ngOnInit 函数内的 console.log。
显然,我遗漏了很多东西,也许有更好的实现方式来实现我需要做的事情,但如果有人能告诉我为什么 Angular 似乎忽略了数组状态的变化,没有在第一次加载后显示各个部分,我将不胜感激,最重要的是为什么每次我访问页面时请求都会成倍增加。