主题 - 对每个下一个值应用更改 [BehaviorSubject.onBeforeNext?]

Subjects - apply changes on every next value [BehaviorSubject.onBeforeNext?]

假设你有一个简单的 BehaviorSubject

this.countryOfBirth$ = new BehaviorSubject<CountryEnum>(null);

get countryOfBirth() {
    return this.countryOfBirth$.value;
};

set countryOfBirth(val: CountryEnum) {
    this.countryOfBirth$.next(val);
};

因此 instance.countryOfBirth returns 最后一个值和 instance.countryOfBirth = CountryEnum.US 将新值推送到主题。

我遇到的问题是我将这个主题实例传递给自定义模型驱动的表单模块,默认情况下会错误地传递字符串而不是我的 CountryEnum class 的实例.

我可以在表单模块中修复此问题,但我希望尽可能将其与任何特定于应用程序的逻辑分离,以便在 BehaviorSubject 实例本身中实施修复更有意义。

我的问题是:是否有挂钩或任何其他方式在每个 "next" 值触发其订阅者之前对每个值应用一些更改?换句话说,在我的代码执行

instance.countryOfBirth = CountryEnum.US;

在触发任何订阅者之前,我想检查该值是否为字符串(例如:US),如果是 - 我想获取相应的 CountryEnum 实例并将其传递给 "next" 调用而不是原来的 "US" 字符串。

在代码中它看起来像

this.countryOfBirth$.onBeforeNext((val) => {
    if (typeof val == "string") {
        return CountryEnum.getInstance(val);
    } else if (val instanceof CountryEnum) {
        return val;
    } else {
        throw new Error("Unsupported value type");
    }
});

但显然 onBeforeNext 不存在,而且我似乎无法在 dox 中找到任何我想要的东西。

非常感谢您的帮助!

因为显然没有现成的方法来做我需要的,这就是我如何使用@estus 在评论中提到的方法来实现我的解决方案:

// BehaviorSubjectWithValidation.ts

import { BehaviorSubject } from "rxjs/BehaviorSubject";

export class BehaviorSubjectWithValidation<T> extends BehaviorSubject<T> {

    private _validator: (val: T) => T;

    constructor(defaultValue: T, validator: (val: T) => T) {
        super(defaultValue);
        this._validator = validator;
    }

    next(value: T): void {
        if (this._validator) {
            value = this._validator(value);
        }
        super.next(value);
    }
}

然后在我的CountryEnumclass我添加了下面的方法

public static parse: (val: any) => CountryEnum = (val: any) => {
    if (val) {
        if (typeof val === "string") {
            return CountryEnum.getInstance(val);
        } else if (val instanceof CountryEnum) {
            return val;
        } else {
            throw new Error("Unsupported CountryEnum value");
        }
    } else {
        throw new Error("Invalid country");
    }
}

然后我在主应用程序的逻辑中按以下方式使用它:

this.countryOfBirth$ = 
    new BehaviorSubjectWithValidation<CountryEnum>(null, CountryEnum.parse);

所以现在我的代码的任何部分都会向 this.countryOfBirth$ 添加一个新值,它总是会通过 CountryEnum.parse.

过滤它

希望这对某人有所帮助!