5

我正在尝试尝试,看看是否有任何聪明的解决方案来创建自定义验证器,这些验证器可以被抽象出来以实现整洁和重用。

在下面的 jsfiddle 中,我只是将一个简单的父模型放在一起,该模型存储和测量数组(只是一个值和一个日期)。在这个例子中,我提出了两个要求。

  1. 每个测量要么提供两个字段,要么都必须提供。
  2. 父数组中必须至少有一个有效(满足先前条件)测量。

    理想情况下,我希望将定义有效的验证逻辑存储在 Measurement 对象中,如下所示。但是,我非常讨厌的是我必须在atLeastOne().

剔除验证将自动验证数字和日期的各个字段但是,我必须介入并针对数组的规则执行验证。

问题:是否有任何方法允许我设置 KO 验证以检查数组是否符合要求,同时仍然让HasValues方法仍然驻留在测量模型中?即我想将搜索“至少一个”的概念抽象为某种可以为我处理工作的自定义验证器,然后告诉这个验证器“嘿,这是我希望你用来验证的函数数组中的每一项。”

提前致谢!

    function Model(data) 
    {
       var self = this;
        self.Measurements = ko.observableArray();

       for(var i = 0; i < data.length; i++)
           self.Measurements.push(new Measurement(data[i]));

        function hasAtLeastOne(){
           var atLeastOne = false;
            $.each(self.Measurements(), function(i, item) { 
                if (item.HasValues()) { 
                   atLeastOne = true; 
                   return; 
                 } 
            });
            return atLeastOne;
        }

        self.Save = function() {               
            if (self.canSave() && atLeastOne())
                alert('save');
            else
                alert('arg!');
        };

        self.errors = ko.validation.group(self);
        self.canSave = ko.computed(function() {
            return self.errors().length == 0;
        });
    }

    function Measurement(data)
    {
       var self = this;
       self.Value = ko.observable(data.val);
       self.Date = ko.observable(data.date);

       self.Value.extend({ required: { onlyIf: isRequired }, number: true });
       self.Date.extend({ required: { onlyIf: isRequired }, date: true });

        self.HasValues = function() {
            return ko.utils.isNotNullUndefOrEmpty(self.Value()) && 
                   self.Date() && self.Date().length > 0;
        };

        function isRequired() {
            return ko.utils.isNotNullUndefOrEmpty(self.Value()) || 
                   (self.Date() && self.Date().length > 0);
        }
    }

    ko.utils.isNotNullUndefOrEmpty = function (value) {
        return (typeof value === 'string' && value.length > 0) || 
               (typeof value !== 'string' && value);
    };

这是一个 jsfiddle 玩,有我的例子:http: //jsfiddle.net/cACZ9/

4

1 回答 1

7

我一直在寻找图书馆资源,看看我是否能发现一些可行的选择。这是我到目前为止发现的。

两种不同的选择都有优点/缺点(当然):

使用自定义验证器:

 ko.validation.rules['AtLeastOne'] = {
        validator: function (array, predicate) {
            var self = this;
            self.predicate = predicate;
            return ko.utils.arrayFirst(array, function (item) {
                return self.predicate.call(item);
            }) != null; 
        },
        message: 'The array must contain at least one valid element.'
    };


  function Modal() {
     var self = this;
     self.Measurements = ko.observableArray().extend({ AtLeastOne: function () {
        return this && this.HasValues();
     }

     ...//refer to OP
     ...
     ...

     self.Save() = function() {
         if (self.errors().length == 0)
           alert('Everything is valid, we can save!');
       else if (!self.Measurements.isValid())
           alert('You must have at least one valid item in the pot!');
     };
  });

这种方法几乎可以将验证从程序员手中拿走,并且非常可重用。但是,我注意到一个潜在的缺点是,每次存储在数组中的任何值(对象或其他)发生突变时,它都会调用自定义验证规则。对大多数人来说可能不是问题。

使用验证器工厂:

 var KoValidationFactory = {
        AtLeastOne: function (measurements, validator) {
            return function () {
                var self = this;
                self.validator = validator;
                return ko.utils.arrayFirst(measurements, function (measurement) {
                            return self.validator.call(measurement);
                        }) != null; 
            };
        }

   };

   function Modal() {
      var self = this;
      self.Measurements = ko.observableArray();

     ...//refer to OP
     ...
     ...

      self.Save = function () {
          var atLeastOneArrayValidator = KoValidationFactory.AtLeastOne(self.Measurements(), function () {
               return this && this.HasValues();
       });
          var arrayWasValid = atLeastOneArrayValidator();
          if (arrayWasValid && self.errors() == 0)
             alert('everything is good, we can save');
          else if (!arrayWasValid)
             alert('You must have at least one item in the pot!');
       };
   }

这种方法可以确保您仅在明确选择时才验证整个数组。不利的一面是您有更多的动手工作,并且没有充分利用淘汰赛验证库。您必须专门验证数组和任何/所有其他采用这种方法的可观察对象,如果它们中有很多,它们可能会变得混乱。

我鼓励对这些方法进行编辑和建议。

于 2012-11-28T20:24:49.017 回答