修改与 angular 异步管道反应方式一起使用的流中的数据
Modify data in stream used with angular async pipe reactive way
iam 尝试使用异步管道而不是手动订阅组件,以防万一,iam 只是显示我从服务器获取的数据,一切正常。但是,如果我以后需要根据某些事件更改显示数据的显示部分怎么办?
例如,我有一个显示时间表的组件,稍后可以被用户接受。我创建了 timesheet$ observable 并在带有异步管道的模板中使用它。为了接受我创建的主题,所以当用户接受时间表时我可以发出。但是我如何组合这两个流(approvementChange$ 和 timesheet$),以便更新 $timesheet?我正在尝试 combineLatest,但它 returns 最新值,所以我无法决定来自 approvementChange 流的值是新值还是旧值。有什么解决办法吗?
export class TimesheetComponent {
errorMessage: string = '';
timesheet$: Observable<Timesheet>;
private approvementSubject = new Subject<TimesheetApprovement>();
approvementChange$ = this.approvementSubject.asObservable();
constructor(
private planService: PlanService,
private statusService: StatusService,
private notifService: NotificationService
) {}
this.timesheet$ = this.statusService.appStatus.pipe(
switchMap((status) => {
return this.planService.getTimesheet(
status.selectedMonth,
status.selectedAgency.agNum
);
})
); //get data every time user changed selected month
approveTimesheet(isApproved: boolean = true) {
const approvement: TimesheetApprovement = {
isApproved: isApproved,
approveTs: new Date(),
isLock: true,
};
this.approvementSubject.next(approvement);
}
}
您只需要跟踪 approvementChange
之后您可以通过 withLatestFrom
选择最新的时间表
approvementChange$
.pipe(withLatestFrom(this.timesheet$))
.subscribe(([accepted, latestTimesheet]) => accepted ? save(latestTimesheet) : void 0)
But what if i need to change displayed part of displayed data later, based on some event?
RxJS 提供了许多运算符来组合、过滤和转换可观察对象。
您可以使用 scan
通过提供接收先前状态和最新发射的函数来维护“状态”。
让我们看一个使用通用 Item
接口的简化示例:
interface Item {
id : number;
name : string;
isComplete : boolean;
}
我们将使用 3 种不同的观察值:
initialItemState$
- 表示项目被获取后的初始状态
itemChanges$
- 代表对我们项目的修改
item$
- 每次应用更改时都会发出我们项目的状态
private itemChanges$ = new Subject<Partial<Item>>();
private initialItemState$ = this.itemId$.pipe(
switchMap(id => this.getItem(id))
);
public item$ = this.initialItemState$.pipe(
switchMap(initialItemState => this.itemChanges$.pipe(
startWith(initialItemState),
scan((item, changes) => ({...item, ...changes}), {} as Item),
))
);
您可以看到我们通过将 initialItemState$
传递给 itemChanges$
可观察对象来定义 item$
。我们使用 startWith
将 initialItemState 发送到更改流中。
所有的魔法都发生在 scan
中,但设置非常简单。我们只是提供一个函数来接受先前的状态和新的变化以及 returns 项目的更新状态。 (在这种情况下,我只是天真地将更改应用到先前的状态;对于您的情况,此逻辑可能需要更复杂。)
这个解决方案是完全反应性的。最终结果是一个干净的 item$
observable,它将在 id 更改或项目发生更改时发出当前项目的更新状态(基于 id)。
这是一个 StackBlitz 您可以看到此行为的地方。
iam 尝试使用异步管道而不是手动订阅组件,以防万一,iam 只是显示我从服务器获取的数据,一切正常。但是,如果我以后需要根据某些事件更改显示数据的显示部分怎么办?
例如,我有一个显示时间表的组件,稍后可以被用户接受。我创建了 timesheet$ observable 并在带有异步管道的模板中使用它。为了接受我创建的主题,所以当用户接受时间表时我可以发出。但是我如何组合这两个流(approvementChange$ 和 timesheet$),以便更新 $timesheet?我正在尝试 combineLatest,但它 returns 最新值,所以我无法决定来自 approvementChange 流的值是新值还是旧值。有什么解决办法吗?
export class TimesheetComponent {
errorMessage: string = '';
timesheet$: Observable<Timesheet>;
private approvementSubject = new Subject<TimesheetApprovement>();
approvementChange$ = this.approvementSubject.asObservable();
constructor(
private planService: PlanService,
private statusService: StatusService,
private notifService: NotificationService
) {}
this.timesheet$ = this.statusService.appStatus.pipe(
switchMap((status) => {
return this.planService.getTimesheet(
status.selectedMonth,
status.selectedAgency.agNum
);
})
); //get data every time user changed selected month
approveTimesheet(isApproved: boolean = true) {
const approvement: TimesheetApprovement = {
isApproved: isApproved,
approveTs: new Date(),
isLock: true,
};
this.approvementSubject.next(approvement);
}
}
您只需要跟踪 approvementChange
之后您可以通过 withLatestFrom
approvementChange$
.pipe(withLatestFrom(this.timesheet$))
.subscribe(([accepted, latestTimesheet]) => accepted ? save(latestTimesheet) : void 0)
But what if i need to change displayed part of displayed data later, based on some event?
RxJS 提供了许多运算符来组合、过滤和转换可观察对象。
您可以使用 scan
通过提供接收先前状态和最新发射的函数来维护“状态”。
让我们看一个使用通用 Item
接口的简化示例:
interface Item {
id : number;
name : string;
isComplete : boolean;
}
我们将使用 3 种不同的观察值:
initialItemState$
- 表示项目被获取后的初始状态itemChanges$
- 代表对我们项目的修改item$
- 每次应用更改时都会发出我们项目的状态
private itemChanges$ = new Subject<Partial<Item>>();
private initialItemState$ = this.itemId$.pipe(
switchMap(id => this.getItem(id))
);
public item$ = this.initialItemState$.pipe(
switchMap(initialItemState => this.itemChanges$.pipe(
startWith(initialItemState),
scan((item, changes) => ({...item, ...changes}), {} as Item),
))
);
您可以看到我们通过将 initialItemState$
传递给 itemChanges$
可观察对象来定义 item$
。我们使用 startWith
将 initialItemState 发送到更改流中。
所有的魔法都发生在 scan
中,但设置非常简单。我们只是提供一个函数来接受先前的状态和新的变化以及 returns 项目的更新状态。 (在这种情况下,我只是天真地将更改应用到先前的状态;对于您的情况,此逻辑可能需要更复杂。)
这个解决方案是完全反应性的。最终结果是一个干净的 item$
observable,它将在 id 更改或项目发生更改时发出当前项目的更新状态(基于 id)。
这是一个 StackBlitz 您可以看到此行为的地方。