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

时间:2016-10-22 00:26:26

标签: angular rxjs behaviorsubject

假设您有一个简单的BehaviorSubject

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

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

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

这样做instance.countryOfBirth会返回最后一个值,而instance.countryOfBirth = CountryEnum.US会将新值推送到主题。

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

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

我的问题是:是否有钩子或任何其他方式对每一个&#34; next&#34;进行一些更改。在它触发订户之前的价值?换句话说,在我的代码之后

instance.countryOfBirth = CountryEnum.US;

在触发任何订阅者之前,我想检查该值是否为字符串(例如:US),如果是 - 我想获取相应的CountryEnum实例并将其传递给&#34; next&# 34;打电话代替原来的&#34;美国&#34;字符串。

在代码中它看起来像

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中找到任何可以做我想做的事情。

非常感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

由于显然没有现成的方法来完成我需要的工作,所以我是如何使用@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);
    }
}

然后在我的CountryEnum课程中,我添加了以下方法

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过滤它。

希望这有助于某人!