修改与 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 您可以看到此行为的地方。