Angular - 如何正确使用服务、HttpClient 和 Observables 在我的应用程序周围传递对象数组
Posted
技术标签:
【中文标题】Angular - 如何正确使用服务、HttpClient 和 Observables 在我的应用程序周围传递对象数组【英文标题】:Angular - How to correctly use Services, HttpClient and Observables to pass an array of objects around my application 【发布时间】:2019-08-29 11:23:57 【问题描述】:我一直在努力理解这一点,很多例子都在谈论 Observables 或 HttpClient 但不是两者都在一起(至少不是我的想法)。
我有一组来自数据库的类别。这些类别有一些属性,并在我的应用程序的几个不同组件中使用。
export class Category
public Id: string = null;
public Name: string = null;
public Order: number = null;
我有一个 Angular 服务,它调用后端来获取类别列表。一些组件具有创建新类别的功能。 在这种情况下,我希望初始列表的所有订阅者都更新为新类别。
export class CategoryService
constructor(private httpClient: HttpClient)
public getCategories(): Observable<Category[]>
return this.httpClient.get<Category[]>('/api/CategoryAdmin/GetCategories');
public addCategory(newCategory: Category)
this.httpClient.post('/api/CategoryAdmin/AddCategory', newCategory).subscribe((result: Category) =>
// what to do here?
, error => console.error(error));
在上面的示例中,我看不出我将如何做到这一点,因此 getCategories() 的初始订阅者将收到已添加的新类别。我想我需要将类别数组存储在 CategoryService 中,然后让每个订阅者订阅它。但是,我很难理解如何正确地做到这一点。我研究了主题,我认为这可能是这样做的方法,但这样做的方法又一次让我失望了。
谁能提供一个例子或指出我正确的方向?
更新:根据下面的答案,我最终将我的代码更新为以下内容。我已经粘贴了整个内容,因为我认为它可以帮助人们更好地理解。
export class CategoryService
constructor(private httpClient: HttpClient)
private _categories = new BehaviorSubject<CommandCategory[]>([]);
private categories: CommandCategory[] = [];
private loading: boolean = false;
public get(): Observable<CommandCategory[]>
this.load();
return this._categories.asObservable();
public load()
if (this.categories.length === 0 && !this.loading)
this.loading = true;
this.httpClient.get<CommandCategory[]>('/api/CategoryAdmin/GetCategories').subscribe((data: CommandCategory[]) =>
this.loading = false;
this.categories = data;
this._categories.next(this.categories);
,
error =>
this.loading = false;
console.log('Could not load categories.');
);
public save(categories: CommandCategory[])
this.httpClient.post('/api/CategoryAdmin/SaveCategories', categories).subscribe(() =>
for (var i = 0; i < categories.length; i++)
if (categories[i].IsDeleted)
categories.splice(i, 1);
this.categories = categories;
this._categories.next(this.categories);
, error => console.log('Could not save categories.'));
public add(category: CommandCategory)
this.httpClient.post('/api/CategoryAdmin/AddCategory', category).subscribe((result: CommandCategory) =>
this.categories.push(result);
this._categories.next(this.categories);
, error => console.error(error));
【问题讨论】:
【参考方案1】:您的两种方法都在不同的地方处理 API 的响应:
getCategories()
只是将检索到的类别列表传递给请求它们的组件/服务。
addCategory()
是实际订阅的CategoryService
所以你在两个不同的地方处理数据存储:
您要么持有服务中的类别列表,而组件使用它(因此您的 addCategory()
方法可以将新创建的类别推送到现有列表中)
或者您像getCategories()
一样将新创建的类别返回给添加它的实体(假设它是拥有完整类别列表的实体)。
编辑:根据您的评论,我已经完成了一个快速的Stackblitz 并可能解决您的问题。它基本上通过async
管道订阅位于service
中的SPOT。
【讨论】:
谢谢。这就是我贫穷的例子。如果我要调整 getCategories 方法以将数组存储在服务中。那么我将如何让其他组件有机会订阅该数组?一个简单的数组不足以做到这一点。大概我会将其设为某种 Observable,然后根据需要将类别推入其中。此外,您如何处理对该数组的初始加载和后续订阅?比如第一次调用后端很明显,但是当第二个组件订阅时,你不想再调用后端吗? 哦,现在我觉得自己很愚蠢。我必须保存一个原始对象数组和一个与之相关的可观察数组。现在我看到它在我面前很有意义。谢谢 @JSG_85 @Piercy 在 stackblitz 示例中提出的解决方案,其中使用of
从数组创建 Observable 并不理想而且相当 hacky。只有在使用 async pipe
和 ChangeDetectionStrategy.Default
时,Angulars 更改检测机制才有效。当您订阅组件或使用ChangeDetectionStrategy.OnPush
时,它不起作用。在这些情况下,使用主题通常会更好。
@fridoo 我实际上最终使用了主题。我只需要在正确的方向上使用额外的数组以及可观察/主题对象。我已经更新了我的问题以显示我最终得到的整个解决方案以上是关于Angular - 如何正确使用服务、HttpClient 和 Observables 在我的应用程序周围传递对象数组的主要内容,如果未能解决你的问题,请参考以下文章
如何正确启动 Angular Universal 到实时服务器
Angular 4:如何正确处理应用程序级别的 http 错误作为 Observable 错误?