Angular/RxJS手动更新管道主题(即使没有数据更改),"rxjs管道中的单位转换"也将自动更新. [英] Angular/RxJS update piped subject manually (even if no data changed), "unit conversion in rxjs pipe"

查看:111
本文介绍了Angular/RxJS手动更新管道主题(即使没有数据更改),"rxjs管道中的单位转换"也将自动更新.的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Angular 9和RxJS 6.5开发应用程序.我在使用Angular服务时遇到问题的功能是从服务器获取某些数据,并将此数据提供给视图(使用RxJS behaviorSubjects).不过,在将数据传递到视图之前,我想进行一些单位转换,以便用户可以使用切换按钮在整个应用程序的两个单位之间进行切换,特别是公吨"和短吨".

虽然在专用服务中提供了实际的转换功能,但我需要控制应转换数据(由服务器获取)的哪些属性,因此我在标配"主题,在内部调用转换方法管道.

 //此"CommoditiesService"从服务器获取数据//并且应该返回所有获取的商品,因此"Commodity []"出口类CommoditiesService {//在此主题内,存储了所有商品(不进行单位转换)私人商品:BehaviorSubject< Commodity []>= new BehaviorSubject(null);公共只读商品:Observable< Commodity []>= this._commodities.pipe(//此管道是商品所有单位转换都在其中进行的地方,//因此,对于每种商品,都会调用函数"convertCommodityUnits".//参数有基本单位和目标单位.基数始终是千克,因为这是服务器返回的值.//目标单位是用户可以全局设置的单位.此"preferredWeightUnit"是在服务内部预订的,因此一旦用户更改单位,它就会更新.map((commodities:Commodity [])=> {//对于每种商品,将价格和库存转换为首选的显示单位返回商品?.map(商品=> this.convertCommodityUnits(商品,"kg",this.preferedWeightUnit))||无效的;}));} 

到目前为止,这就像一个魅力:单位已转换,视图可以订阅可观察的商品.现在的问题是,当用户更新"preferredWeightUnit"时,不会重新评估可观察到的商品",因此在CommoditiesService中更新了"this.preferredWeightUnit",但不再进行单位转换.

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

首选单位更改后,如何再次触发单位转换(即RxJS管道)?此外,这种设计选择是否甚至是使单元以反应性方式进行更换的好主意?我认为最好在可能出现的任何地方更改视图中的单位.

解决方案

您可以使用

I am working on an app using Angular 9 and RxJS 6.5. The functionality I have problems with uses Angular services to fetch some data from a server and provides this data to views (using RxJS behaviorSubjects). Before passing that data to the views though, I want to do some unit conversion, so that the user can use a toggle/switch to change between two units for the entire app, specifically "metric tons" and "short tons".

While the actual conversion functions are provided within a dedicated service, I need to control which properties of the data (that was fetched by the server) should be converted, so I am "piping" the subjects, calling the conversion methods inside the pipe.

// 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;
    })
  );
}

So far this works like a charm: The units are converted and views can subscribe to the commodities observable. The problem is now, when the user updates the "preferredWeightUnit", the "commodities" observable is not re-evaluated, so "this.preferredWeightUnit" is updated inside CommoditiesService, but the unit conversion is not done again.

I suppose I could update the subject with the same data, so calling this._commodities.next(this._commodities.value), but this just looks wrong to me.

How could I trigger the unit conversion (so the RxJS pipe) again once the prefered unit changed? Also, is this design choice even a good idea to make the units changable in a reactive way? I thought it was better then changing the units inside views everywhere they might appear.

解决方案

You can incorporate changes from multiple observable sources using the combineLatest operator.

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;
        })
    );
}

这篇关于Angular/RxJS手动更新管道主题(即使没有数据更改),"rxjs管道中的单位转换"也将自动更新.的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆