3

我对淘汰赛还很陌生,并且正在尝试弄清楚如何将我理解的两部分放在一起。

我需要:

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

例子:

  • 我有startTime几秒钟,duration几秒钟,stopTime这是从startTime + duration
  • startTime无法改变
  • durationstopTime绑定到输入字段
  • stopTimeHH:MM:SS格式显示和输入
  • 如果用户发生变化stopTimeduration应计算并自动更新
  • 如果用户发生变化durationstopTime应计算并自动更新

我可以让它们相互更新(假设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到第一个块中的计算它不起作用,因为到 timeHMSValidatevalidate函数获取它已经被更改的值。

我通过添加另一个可观察到的来跟踪传递给计算的“原始”值,然后添加另一个使用该值来确定它是否是错误状态的计算,从而使其在第一个块中工作,但这不是感觉很优雅。

有没有更好的办法?

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

4

1 回答 1

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

这样做是创建另一个计算的 observable,它充当原始 observable 的前端/过滤器。该 observable 有一些其他的 sub-observables,hasError并且errorMessage附加到它的错误状态。跟踪输入的rawValue值,以便我们可以检测它是否是一个好的值。这处理了我要求的验证一半。

至于使两个值相互依赖,我问题中的原始代码有效。为了使其得到验证,我添加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() 中),所以如果有人想出另一种方法来做到这一点,我就是耳朵。

于 2013-09-03T20:58:39.557 回答