淘汰计算和输入验证

Knockout computed and input validation

本文关键字:验证 输入 计算 淘汰      更新时间:2023-09-26

我对淘汰赛还很陌生,正在努力想办法把我理解的两个部分放在一起。

我需要:

  1. 相互依赖的项目
  2. 项目的输入值验证

示例:

  • 我有以秒为单位的startTime,以秒为单元的duration,以及根据startTime + duration计算的stopTime
  • startTime无法更改
  • CCD_ 6和CCD_
  • stopTimeHH:MM:SS格式显示和输入
  • 如果用户更改stopTime,则应计算并自动更新duration
  • 如果用户更改duration,则应计算并自动更新stopTime

我可以让它们相互更新(假设Sec2HMSHMS2Sec在其他地方定义,并在HH:MM:SS和秒之间转换):

this.startTime = 120; // Start at 120 seconds
this.duration = ko.observable(0);
// This dependency works by itself.
this.stopTimeFormatted = ko.computed({
    read: function () {
        return Sec2HMS(this.startTime + parseInt(this.duration()), true);
    },
    write: function (value) {
        var stopTimeSeconds = HMS2Sec(value);
        if (!isNaN(stopTimeSeconds)) {
            this.duration(stopTimeSeconds - this.startTime);
        } else {
            this.duration(0);
        }
    },
    owner: this
});

或者,我可以使用extendersfn来验证输入,如敲除文档中所示:

ko.subscribable.fn.HMSValidate = function (errorMessage) {
    //add some sub-observables to our observable
    var observable = this;
    observable.hasError = ko.observable();
    observable.errorMessage = ko.observable();
    function validate(newValue) {
        var isInvalid = isNaN(HMS2Sec(newValue));
        observable.hasError(isInvalid ? true : false);
        observable.errorMessage(isInvalid ? errorMessage : null);
    }
    //initial validation
    validate(observable());
    //validate whenever the value changes
    observable.subscribe(validate);
    //return the original observable
    return observable;
};
this.startTime = 120; // Start at 120 seconds
this.duration = ko.observable(0);
this.stopTimeHMS = ko.observable("00:00:00").HMSValidate("HH:MM:SS please");

但我该如何让他们一起工作呢?如果我把HMSValidate加到第一个块中计算的值上,它就不起作用了,因为当HMSValidatevalidate函数得到值时,它已经改变了。

我已经在第一个块中实现了这一点,添加了另一个可观察的值,它可以跟踪传递到计算中的"原始"值,然后添加另一个使用该值来决定是否为错误状态的计算值,但这感觉不太优雅。

有更好的方法吗?

http://jsfiddle.net/cygnl7/njNaS/2/

在解决了一周没有解决方法的问题(代码清理时间!)后,我又回到了这里,这就是我所拥有的。

我最终提出了我在问题结尾提到的想法,但将其封装在fn中。

ko.subscribable.fn.hmsValidate = function (errorMessage) {
    var origObservable = this;
    var rawValue = ko.observable(origObservable()); // Used for error checking without changing our main observable.
    if (!origObservable.hmsFormatValidator) {
        // Handy place to store the validator observable
        origObservable.hmsFormatValidator = ko.computed({
            read: function () {
                // Something else could have updated our observable, so keep our rawValue in sync.
                rawValue(origObservable());
                return origObservable();
            },
            write: function (newValue) {
                rawValue(newValue);
                if (newValue != origObservable() && !isNaN(HMS2Sec(newValue))) {
                    origObservable(newValue);
                }
            }
        });
        origObservable.hmsFormatValidator.hasError = ko.computed(function () {
            return isNaN(HMS2Sec(rawValue()));
        }, this);
        origObservable.hmsFormatValidator.errorMessage = ko.computed(function () {
            return errorMessage;
        }, this);
    }
    return origObservable.hmsFormatValidator;
};

这样做的目的是创建另一个计算的可观测值,该可观测值充当原始可观测值的前沿/滤波器。对于误差状态,该可观测值具有一些其他子可观测值hasErrorerrorMessagerawValue会在输入时跟踪该值,以便我们可以检测它是否是一个好值。这处理了我一半需求的验证。

至于使两个值相互依赖,我问题中的原始代码是有效的。为了验证它,我添加了hmsValidate,如下所示:

this.stopTimeFormatted = ko.computed({
    read: function () {
        return Sec2HMS(this.startTime + parseInt(this.duration()), true);
    },
    write: function (value) {
        this.duration(HMS2Sec(value) - this.startTime);
    },
    owner: this
}).hmsValidate("HH:MM:SS please");

请在此处查看其实际操作:http://jsfiddle.net/cygnl7/tNV5S/1/

值得注意的是,write内部的验证不再是必要的,因为只有在正确验证的情况下,hmsValidate才会写入该值。

这对我来说仍然有点不雅,因为我检查了几次isNaN,并且必须跟踪原始值(尤其是在read()中),所以如果有人想出另一种方法来做这件事,我会洗耳恭听。