自定义验证导致计算值触发

时间:2014-06-14 18:06:00

标签: validation knockout.js

为了快速查看我的问题,我制作了一个有效的jsFiddle here

在KnockoutJS中,我制作了一个自定义扩展器验证器来测试输入格式是否为HHMM格式。如果是,则返回新值,如果不是,则将其设置回当前正在运行的旧值。

ko.extenders.acValidTimeHHMM = function (target, options) {
var result = ko.computed({
    read: target, 
    write: function (newValue) {
        var re = /^([0-9]|0[0-9]|1[0-9]|2[0-3])[0-5][0-9]$/;
        if (!re.test(newValue)) {
            target.notifySubscribers(target());
            //Time not in correct format return old time
            return;
        }
        target(newValue);
    }
}).extend({ notify: 'always' });

result(target());
return result;
};

我遇到的问题是,当使用计算值更改值时,我会更新数据库。但是,当我使用验证器将值重置回原始值时,这也会触发。 (基于Ryan Rahlf脏旗技术的方法here

self.update = ko.computed(function () {
    self.timeOne();
    self.timeTwo();
    alert("Fired");
});

问题显然是行target.notifySubscribers(target());在我的验证器中。但是如果没有这一行,我无法将值重置为旧值,我找不到另一种方法来执行此操作。

所以这只会在值实际发生变化时触发,而不是验证者重置它。 jsFiddle完全展示了我的问题,可以用来制作一个工作版本(希望如此)我知道它目前也在页面加载时触发。

1 个答案:

答案 0 :(得分:0)

  

我遇到的问题是,当使用计算值更改值时,我会更新数据库。

我不知道你的所有逻辑,但我不认为每次你的淘汰视图模型更新时更新数据库是个好主意。你应该看看knockout validation plugin。使用此插件,您可以构建相同的自定义验证规则,并仅在表单提交事件上更新数据库。

关于你的问题...... 我找到的最简单的解决方案是将一个成功的回调函数发送到验证扩展,就像一个选项。 类似于this

JS:

var ViewModel = function() {  
    var update = function () {
        alert("value was successfully changed");
    };

    var cancel = function () {
        alert("validation failed. previous value was returned");
    };

    var timeOne = ko.observable("1100").
        extend({ 
                    acValidTimeHHMM: { 
                        success: update,
                        fail: cancel
                    }
               });

    var timeTwo = ko.observable("1248").
        extend({ acValidTimeHHMM: { success: update } });

    return {
        timeOne: timeOne,
        timeTwo: timeTwo
    };
};

ko.extenders.acValidTimeHHMM = function(target, option) {    
    var baseOptions = {
        success: null,
        fail: null
    };
    $.extend(baseOptions, option);

    var result = ko.computed({
        read: target, 
        write: function (newValue) {
            var oldValue = target();
            if(newValue == oldValue) return;

            var re = /^([0-9]|0[0-9]|1[0-9]|2[0-3])[0-5][0-9]$/;
            if (!re.test(newValue)) {
                target.notifySubscribers(oldValue);
                if(typeof(baseOptions.fail) == "function")
                    baseOptions.fail();
                return;
            }
            target(newValue);

            if(typeof(baseOptions.success) == "function")
                baseOptions.success()
        }
    }).extend({ notify: 'always' });

    result(target());
    return result;
};

ko.applyBindings(new ViewModel());

HTML:

<p>Time One<input data-bind='value: timeOne' /></p> 
<p>Time Two<input data-bind='value: timeTwo' /></p>