调用函数时清除 Observable 值
Clear Observable value when calling function
我有一个从服务中获取值的下拉列表。
下拉菜单
<mat-select
*ngIf="selectedCloudTypeName === 'AWS'"
class="select--width--130"
[formControl]="awsOwnersControl"
placeholder="AWS Owners"
msInfiniteScroll
(infiniteScroll)="loadMoreAwsOwners()"
[complete]="currentAwsOwnerssDropdownOffset >= awsOwnersTotalCount"
>
<mat-option *ngFor="let owner of awsOwners$ | async" [value]="owner.id">
{{ owner.name }}
</mat-option>
</mat-select>
TS 文件中的服务调用
getAwsOwners(offset = 0) {
this.isLoading$.next(true);
this.awsService
.getOwnersListForAws(this.selectedCredentialIdForCloudType, this.selectedPlatform, { offset, limit: 100 })
.subscribe(
(owners: PaginatedResult<CommonEnumValue[]>) => {
this.awsOwners.next(owners.data);
this.awsOwnersTotalCount = owners.totalCount;
this.isLoading$.next(false);
},
(error) => {
this.isLoading$.next(false);
this.alertify.error(error);
},
);
}
在 OnInit 钩子中我使用了一个 Observable
this.awsOwners$ = this.awsOwners.asObservable().pipe(scan((acc, curr) => [...acc, ...curr], []));
我在文件中声明为 属性 为
awsOwners = new BehaviorSubject<CommonEnumValue[]>([]);
awsOwners$: Observable<CommonEnumValue[]>;
问题是当我用不同的 'selectedPlatform' 值调用 getAwsOnwers 函数时,旧数据仍然存在,新数据被追加。
我试过像这样清除 awsOwners 主题
this.awsOwners.next([]);
在我调用它之前它确实清除了它并且新数据附加到旧数据,
有什么方法可以清除它吗?
我感觉到在扫描运算符中我需要清除“.acc”,因为它会累积值。
如果扫描 lambda 中的 curr
值为空,您可以重置扫描。
(acc, curr) => curr === [] ? [] : [...acc, ...curr]
但这对我来说有点脏。
一种更简洁的方法是在您希望重置后重新订阅您的 scan observable。
您可以创建一个 BehaviourSubject 并在每次您希望重置值时发出。
然后你可以将你的主题和 switchMap 传递给你的 scan observable。
这样,可观察对象将始终重新订阅您的扫描可观察对象,从而重新开始,因为如果源发出值,switchMap 会自动取消订阅和订阅。
可能看起来像这样:
BehaviourSubject resetSubject$ = new BehaviourSubject<void>(); // use behaviour subject to get an initial emit
awsOwners$ = resetSubject$.pipe(
switchMap(() => this.awsOwners.asObservable().pipe(
scan((acc, curr) => [...acc, ...curr], [])
),
);
// call this to reset your scan
resetSubject$.emit()
- 从
this.awsOwners$
管道中删除 scan
this.awsOwners$ = this.awsOwners.asObservable()
- 将
this.selectedPlatform
作为主题,如果更改则使其调用 getAwsOwners
this._selectedPlatform$ = new Subject()
get selectedPlatform$() {
// if platform is object you should provide comparing callback to distinctUntilChanged operator
return this._selectedPlatform$.asObservable.pipe(distinctUntilChanged(), tap(() =>
//make getAwsOwners() accept platform as an parameter and offset as a optional one.
this.getAwsOwners(platform);
))
}
- 在
getAwsOwners
订阅方法中进行一些更改
.subscribe(
(owners: PaginatedResult<CommonEnumValue[]>) => {
// always if offset === 0 you should reset owners state
this.awsOwners.next(offset ?
[...this.awsOwners.getValue(), ...owners.data] :
owners.data
);
this.awsOwnersTotalCount = owners.totalCount;
this.isLoading$.next(false);
},
(error) => {
this.isLoading$.next(false);
this.alertify.error(error);
},
);
无需使用更新主题的方法,只需创建一个流来维护列表数据的状态(如果正在加载)和当前页面偏移量。
readonly offsetChangeSubject = new Subject<number>();
readonly selectedPlatformSubject = new Subject<string>();
readonly ownersList$ = this.selectedPlatformSubject.pipe(
switchMap(platform) => offsetChangeSubject.pipe(
startWith(0),
mergeScan((acc, offset) =>
this.awsService.getOwnersListForAws(this.credentialId, platform, { offset, limit: 100 }).pipe(
startWith({ ...acc, isLoading: true, offset })
map(page => ({
isLoading: false,
offset,
owners: owners.concat(page.data),
totalCount: page.totalCount
}))
),
{ isLoading: false, owners: [], totalCount: 0, offset }
)
))
)
- 偏移量和平台参数转换为主题。
- 主观察对象是从平台主题创建的。
- 主要可观察对象中的唯一运算符是 switchMap。这会导致任何现有请求立即被取消。
- 在 switchMap 中,订阅了 offsetChanges。由于 startWith 运算符,它会立即发出 0。
- offsetChanges 的任何排放都将立即启动 mergeScan 内的所有者请求。这将使用之前发射的数据,并为每个请求发射两次,以便管理加载状态。
备注
如果不明显,platformSubject 首次发出后总会有结果。
我猜想一旦那个平台改变了,你也会想要重置偏移量,这就是我没有做的原因之一
offsetSubject 一个 BehaviorSubject 而不是使用 startWith 来发出
0. 所以你会从 ownersList$ observable 中检索偏移量的当前值,而不是 offsetChangeSubject - 那只是
更新。
如果您希望当前列表状态不仅仅显示在视图中,您可以使用 shareReplay。
我有一个从服务中获取值的下拉列表。
下拉菜单
<mat-select
*ngIf="selectedCloudTypeName === 'AWS'"
class="select--width--130"
[formControl]="awsOwnersControl"
placeholder="AWS Owners"
msInfiniteScroll
(infiniteScroll)="loadMoreAwsOwners()"
[complete]="currentAwsOwnerssDropdownOffset >= awsOwnersTotalCount"
>
<mat-option *ngFor="let owner of awsOwners$ | async" [value]="owner.id">
{{ owner.name }}
</mat-option>
</mat-select>
TS 文件中的服务调用
getAwsOwners(offset = 0) {
this.isLoading$.next(true);
this.awsService
.getOwnersListForAws(this.selectedCredentialIdForCloudType, this.selectedPlatform, { offset, limit: 100 })
.subscribe(
(owners: PaginatedResult<CommonEnumValue[]>) => {
this.awsOwners.next(owners.data);
this.awsOwnersTotalCount = owners.totalCount;
this.isLoading$.next(false);
},
(error) => {
this.isLoading$.next(false);
this.alertify.error(error);
},
);
}
在 OnInit 钩子中我使用了一个 Observable
this.awsOwners$ = this.awsOwners.asObservable().pipe(scan((acc, curr) => [...acc, ...curr], []));
我在文件中声明为 属性 为
awsOwners = new BehaviorSubject<CommonEnumValue[]>([]);
awsOwners$: Observable<CommonEnumValue[]>;
问题是当我用不同的 'selectedPlatform' 值调用 getAwsOnwers 函数时,旧数据仍然存在,新数据被追加。
我试过像这样清除 awsOwners 主题
this.awsOwners.next([]);
在我调用它之前它确实清除了它并且新数据附加到旧数据,
有什么方法可以清除它吗?
我感觉到在扫描运算符中我需要清除“.acc”,因为它会累积值。
如果扫描 lambda 中的 curr
值为空,您可以重置扫描。
(acc, curr) => curr === [] ? [] : [...acc, ...curr]
但这对我来说有点脏。
一种更简洁的方法是在您希望重置后重新订阅您的 scan observable。
您可以创建一个 BehaviourSubject 并在每次您希望重置值时发出。 然后你可以将你的主题和 switchMap 传递给你的 scan observable。 这样,可观察对象将始终重新订阅您的扫描可观察对象,从而重新开始,因为如果源发出值,switchMap 会自动取消订阅和订阅。
可能看起来像这样:
BehaviourSubject resetSubject$ = new BehaviourSubject<void>(); // use behaviour subject to get an initial emit
awsOwners$ = resetSubject$.pipe(
switchMap(() => this.awsOwners.asObservable().pipe(
scan((acc, curr) => [...acc, ...curr], [])
),
);
// call this to reset your scan
resetSubject$.emit()
- 从
this.awsOwners$
管道中删除scan
this.awsOwners$ = this.awsOwners.asObservable()
- 将
this.selectedPlatform
作为主题,如果更改则使其调用getAwsOwners
this._selectedPlatform$ = new Subject()
get selectedPlatform$() {
// if platform is object you should provide comparing callback to distinctUntilChanged operator
return this._selectedPlatform$.asObservable.pipe(distinctUntilChanged(), tap(() =>
//make getAwsOwners() accept platform as an parameter and offset as a optional one.
this.getAwsOwners(platform);
))
}
- 在
getAwsOwners
订阅方法中进行一些更改
.subscribe(
(owners: PaginatedResult<CommonEnumValue[]>) => {
// always if offset === 0 you should reset owners state
this.awsOwners.next(offset ?
[...this.awsOwners.getValue(), ...owners.data] :
owners.data
);
this.awsOwnersTotalCount = owners.totalCount;
this.isLoading$.next(false);
},
(error) => {
this.isLoading$.next(false);
this.alertify.error(error);
},
);
无需使用更新主题的方法,只需创建一个流来维护列表数据的状态(如果正在加载)和当前页面偏移量。
readonly offsetChangeSubject = new Subject<number>();
readonly selectedPlatformSubject = new Subject<string>();
readonly ownersList$ = this.selectedPlatformSubject.pipe(
switchMap(platform) => offsetChangeSubject.pipe(
startWith(0),
mergeScan((acc, offset) =>
this.awsService.getOwnersListForAws(this.credentialId, platform, { offset, limit: 100 }).pipe(
startWith({ ...acc, isLoading: true, offset })
map(page => ({
isLoading: false,
offset,
owners: owners.concat(page.data),
totalCount: page.totalCount
}))
),
{ isLoading: false, owners: [], totalCount: 0, offset }
)
))
)
- 偏移量和平台参数转换为主题。
- 主观察对象是从平台主题创建的。
- 主要可观察对象中的唯一运算符是 switchMap。这会导致任何现有请求立即被取消。
- 在 switchMap 中,订阅了 offsetChanges。由于 startWith 运算符,它会立即发出 0。
- offsetChanges 的任何排放都将立即启动 mergeScan 内的所有者请求。这将使用之前发射的数据,并为每个请求发射两次,以便管理加载状态。
备注
如果不明显,platformSubject 首次发出后总会有结果。
我猜想一旦那个平台改变了,你也会想要重置偏移量,这就是我没有做的原因之一 offsetSubject 一个 BehaviorSubject 而不是使用 startWith 来发出 0. 所以你会从 ownersList$ observable 中检索偏移量的当前值,而不是 offsetChangeSubject - 那只是 更新。
如果您希望当前列表状态不仅仅显示在视图中,您可以使用 shareReplay。