【问题标题】:Angular/RxJS update piped subject manually (even if no data changed), "unit conversion in rxjs pipe"Angular/RxJS 手动更新管道主题(即使没有更改数据),“rxjs 管道中的单位转换”
【发布时间】:2020-05-11 10:35:57
【问题描述】:

我正在开发一个使用 Angular 9 和 RxJS 6.5 的应用程序。我遇到问题的功能使用 Angular 服务从服务器获取一些数据并将这些数据提供给视图(使用 RxJS 行为主题)。不过,在将该数据传递给视图之前,我想做一些单位转换,以便用户可以使用切换/开关在整个应用程序的两个单位之间进行切换,特别是“公吨”和“短吨”。

虽然在专用服务中提供了实际的转换功能,但我需要控制应该转换数据的哪些属性(由服务器获取),所以我正在“管道”主题,调用内部的转换方法管道。

// This "CommoditiesService" fetches data from the server
// and should return all fetched commodities, so "Commodity[]"
export class CommoditiesService {
    // Inside this subject, all Commodities are stored (without unit conversion)
    private _commodities: BehaviorSubject<Commodity[]> = new BehaviorSubject(null);

   public readonly commodities: Observable<Commodity[]> = this._commodities.pipe(
    // This pipe is where all unit conversions for commodities is happening,
    // so for every commodity, the function "convertCommodityUnits" is called.
    // the arguments there are the base and the target unit. Base is always kilogram, as this is what the server returns.
    // The target unit is what the user can set globally. This "preferredWeightUnit" is subscribed to inside the service, so it is updated once the user changes the unit.

    map((commodities: Commodity[]) => {
      // For every commodity, convert Price and inventory into the prefered display unit
      return commodities?.map(commodity => this.convertCommodityUnits(commodity, "kg", this.preferedWeightUnit)) || null;
    })
  );
}

到目前为止,这就像一个魅力:单位被转换并且视图可以订阅可观察的商品。 现在的问题是,当用户更新“preferredWeightUnit”时,“commodities” observable 没有被重新评估,所以“this.preferredWeightUnit”在 CommoditiesService 内部被更新,但是单位转换没有再次进行。

我想我可以用相同的数据更新主题,所以调用this._commodities.next(this._commodities.value),但这对我来说似乎是错误的。

一旦首选单位更改,我如何再次触发单位转换(因此 RxJS 管道)? 此外,这种设计选择是否是使单元以反应方式可变的好主意?我认为最好在可能出现的任何地方更改视图内的单位。

【问题讨论】:

    标签: angular rxjs angular-services rxjs-pipeable-operators rxjs-observables


    【解决方案1】:

    您可以使用 combineLatest 运算符合并来自多个可观察源的更改。

    export class CommoditiesService {
        private _commodities: BehaviorSubject<Commodity[]> = new BehaviorSubject(null);
    
        public readonly commodities: Observable<Commodity[]> = combineLatest([this._commodities, this.preferredWeightUnit$]).pipe(
            map(([commodities: Commodity[], weightUnit]) => {
               return commodities?.map(commodity => this.convertCommodityUnits(commodity, "kg", weightUnit)) || null;
            })
        );
    }
    

    【讨论】:

    • 太棒了,谢谢。像预期的那样工作!我怎么会不知道,好厉害!
    猜你喜欢
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 2020-03-26
    • 1970-01-01
    相关资源
    最近更新 更多