敲除验证在列表中是唯一的

时间:2013-10-17 22:54:07

标签: javascript knockout.js knockout-validation

我正在尝试使用ko.validation验证列表中的条目是否与列表中的所有其他条目都是唯一的,但是在运行验证时我遇到了问题。

我有一个可编辑的列表(ko.observableArray),该数组中的每个项目都是一个视图模型,上面有ko.observable

var vm = function (data) {
    var self = this;

    self.items = ko.observableArray();

    _.each(data.words, function (word) {
        self.items.push(new listItemVm({parent: self, word: word.word}));
    });
};

var listItemVm = function (data) {
    var self = this;
    self.parent = data.parent;
    self.word = ko.observable(data.word);
};

然后我向listItemVm.word ko.observable添加一些验证。我希望每个人都是独一无二的:

var listItemVm = function (data) {
    var self = this;
    self.parent = data.parent;
    self.word = ko.observable(data.word).extend({
        validation: {
            validator: function (name, params) {
                console.log("validating " + name);
                // word we are editing must be different from all other words

                // uncommenting this next line causes the behaviour
                // I would expect because params.parent.items() 
                // is not called
                //return true;

                var allWords = params.parent.items();

                // exclude current view model we are editing
                var otherWordViewModels = _.filter(allWords, function (row) {
                    return row !== params.currentRow;
                });

                var otherWords = _.map(otherWordViewModels, function (item) {
                    return item.word();
                });

                return !_.contains(otherWords, name);
            },
            message: 'Must be unique',
            params: {
                currentRow: self,
                parent: self.parent
            }
        }
    });
};

我给它一些数据,并将其包装在一些HTML中:http://jsfiddle.net/9kw75/3/

现在,这确实工作 - 验证运行正确并且当两个输入的值相等时显示无效 - 但是看看控制台上的那个小提琴。为什么验证例程在加载时运行三次,为什么两个字段只在一个值更新时验证?

  • 页面加载
    • 预期:每个输入字段都会运行一次验证。
    • 实际:一次输入验证运行三次,另一次输入验证两次。
  • 关于值更新(输入字段)
    • 预期:仅针对更改的输入字段运行验证
    • 实际:两个输入字段都运行验证

值得注意的是,只有在验证器中读取params.parent.items()后才能观察到这种奇怪的行为。如果返回被注释掉,我会发现我期望的行为。

1 个答案:

答案 0 :(得分:2)

我相信它的工作方式是“验证器”函数用于计算的observable。因此,在执行时读取的任何可观察对象现在都是依赖性用于计算。由于您正在阅读此函数中每个项目的word可观察项,因此每个项目都会触发所有其他项目的验证。

它是有意义的,它以这种方式工作,但在您的特定应用程序的情况下,它没有意义。您可以使用peek来读取observable而不触发依赖项检测:

var allWords = params.parent.items.peek();

// ...

var otherWords = _.map(otherWordViewModels, function (item) {
    return item.word.peek();
});