我有一个 Angular 服务,它调用 API 并获取页面列表。这些页面是从多个组件订阅的。考虑到这一点,我使用BehaviorSubjects 来确保每个订阅者都能获得更新。
当我想添加一个新页面时,我需要向服务器提交一个HTTP POST请求,并处理响应。在处理它时,我需要更新一个数组,然后调用 next() 将更新发送给所有订阅者。这要求我在 HTTP 调用上有一个订阅者(至少,我认为是这样),以便我可以调用 next()。但是,在调用 next 时,我还希望组件能够更新并让用户知道请求已完成。
这是一个 stackblitz 示例。在 app.component.ts 中,第 38 行调用服务来创建页面。下面是一段注释掉的代码,它将订阅并将 isSaving 变量设置为 false。但是,我无法订阅该方法,因为它已经在pages.service.ts 文件中进行了订阅。
https://stackblitz.com/edit/angular-abi4mn
我希望这个例子比我的胡言乱语更有意义,如果解释不好,我深表歉意。
当前您在 PagesService 中订阅了可观察对象,调用该方法的组件应该改为订阅它。因此,在您的
PagesService.add
中,您应该返回可观察量,并且可以在调用组件中订阅可观察量:this.pagesService.add(newPage).subscribe(...)
。
现在,由于您还想在 POST 请求成功后在 PagesService 中执行操作,因此您可以使用 tap
运算符对可观察结果进行
spy操作,而不会影响它,如下所示:
页面服务:
public add(page): Observable<any> {
return this.httpClient
.post('https://my-json-server.typicode.com/typicode/demo/posts', page)
.pipe(
tap(() => {
this.pages.push(page);
this._pages.next(this.pages);
}),
);
}
如果要更新同一页面上的页面数组,请使用 _pages observable 而不是局部变量 page。您只需要做三处更改。
<p>
In the real life example there will be multiple subscribers to the pages array on the pages service. When I add to the array, i need to contact the backend server as well as, update the array so the subscribers can pick up the change.
</p>
<p>
As well as updating the array, it would be nice for the component thats submitting the call to know when the save has completed. This way i can display some visual information to the user. In this example i use the isSaving variable. This is the part i dont know how to handle, i want to add to the pages array, but also have the component subscribe to the http call so that it can do some stuff once the call is complete.
</p>
<p>
Number of Pages: <strong>{{(pagesService._pages | async).length}}</strong> <br /> <br />
<button (click)="addPage()" [disabled]="isSaving">Add Page</button>
</p>
将 _pages 变量的 private 设置为 public 到服务中。
public _pages = new BehaviorSubject<any[]>([]);
第三个更改需要更新 isSaving 变量。
public getPages() {
this.pagesService.get().subscribe((result: any[]) => {
this.pages = result;
this.isSaving = false;
}, error => {
console.error(error);
});
}
我已经测试了所有场景并且工作正常。 如果您有任何疑问,请告诉我。 谢谢。